krkn-lib 5.1.7__tar.gz → 5.1.13__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.1.7 → krkn_lib-5.1.13}/PKG-INFO +3 -2
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/pyproject.toml +3 -2
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/k8s/krkn_kubernetes.py +424 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/k8s/pod_monitor/pod_monitor.py +143 -54
- krkn_lib-5.1.13/src/krkn_lib/k8s/templates/snapshot.j2 +10 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/models/elastic/models.py +25 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/models/pod_monitor/models.py +4 -4
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/models/telemetry/models.py +14 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/tests/base_test.py +18 -1
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/tests/test_krkn_elastic_models.py +27 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/tests/test_krkn_kubernetes_check.py +6 -2
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/tests/test_krkn_kubernetes_list.py +46 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/tests/test_krkn_kubernetes_pods_monitor.py +4 -1
- krkn_lib-5.1.13/src/krkn_lib/tests/test_krkn_kubernetes_virt.py +790 -0
- krkn_lib-5.1.13/src/krkn_lib/tests/test_krkn_openshift.py +645 -0
- krkn_lib-5.1.13/src/krkn_lib/tests/test_krkn_telemetry_kubernetes.py +850 -0
- krkn_lib-5.1.13/src/krkn_lib/tests/test_safe_logger.py +494 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/utils/functions.py +7 -8
- krkn_lib-5.1.7/src/krkn_lib/tests/test_krkn_openshift.py +0 -123
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/LICENSE +0 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/README.md +0 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/__init__.py +0 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/aws_tests/__init__.py +0 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/aws_tests/test_krkn_telemetry_kubernetes.py +0 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/aws_tests/test_krkn_telemetry_openshift.py +0 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/elastic/__init__.py +0 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/elastic/krkn_elastic.py +0 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/k8s/__init__.py +0 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/k8s/pod_monitor/__init__.py +0 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/k8s/templates/hog_pod.j2 +0 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/k8s/templates/node_exec_pod.j2 +0 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/k8s/templates/service_hijacking_config_map.j2 +0 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/k8s/templates/service_hijacking_pod.j2 +0 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/k8s/templates/syn_flood_pod.j2 +0 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/models/__init__.py +0 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/models/elastic/__init__.py +0 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/models/k8s/__init__.py +0 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/models/k8s/models.py +0 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/models/krkn/__init__.py +0 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/models/krkn/models.py +0 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/models/pod_monitor/__init__.py +0 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/models/telemetry/__init__.py +0 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/ocp/__init__.py +0 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/ocp/krkn_openshift.py +0 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/prometheus/__init__.py +0 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/prometheus/krkn_prometheus.py +0 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/telemetry/__init__.py +0 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/telemetry/k8s/__init__.py +0 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/telemetry/k8s/krkn_telemetry_kubernetes.py +0 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/telemetry/ocp/__init__.py +0 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/telemetry/ocp/krkn_telemetry_openshift.py +0 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/tests/__init__.py +0 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/tests/test_krkn_elastic.py +0 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/tests/test_krkn_kubernetes_create.py +0 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/tests/test_krkn_kubernetes_delete.py +0 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/tests/test_krkn_kubernetes_exec.py +0 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/tests/test_krkn_kubernetes_get.py +0 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/tests/test_krkn_kubernetes_misc.py +0 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/tests/test_krkn_kubernetes_models.py +0 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/tests/test_krkn_kubernetes_pods_monitor_models.py +0 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/tests/test_krkn_prometheus.py +0 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/tests/test_krkn_telemetry_models.py +0 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/tests/test_utils.py +0 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/tests/test_version.py +0 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/utils/__init__.py +0 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/utils/safe_logger.py +0 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/version/__init__.py +0 -0
- {krkn_lib-5.1.7 → krkn_lib-5.1.13}/src/krkn_lib/version/version.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: krkn-lib
|
|
3
|
-
Version: 5.1.
|
|
3
|
+
Version: 5.1.13
|
|
4
4
|
Summary: Foundation library for Kraken
|
|
5
5
|
License: Apache-2.0
|
|
6
6
|
License-File: LICENSE
|
|
@@ -21,8 +21,9 @@ Requires-Dist: cython (==3.0)
|
|
|
21
21
|
Requires-Dist: deprecation (==2.1.0)
|
|
22
22
|
Requires-Dist: elasticsearch (==7.13.4)
|
|
23
23
|
Requires-Dist: elasticsearch-dsl (==7.4.1)
|
|
24
|
+
Requires-Dist: importlib-metadata (>=8.7.0,<9.0.0)
|
|
24
25
|
Requires-Dist: kubeconfig (>=1.1.1,<2.0.0)
|
|
25
|
-
Requires-Dist: kubernetes (==
|
|
26
|
+
Requires-Dist: kubernetes (==34.1.0)
|
|
26
27
|
Requires-Dist: numpy (==1.26.4)
|
|
27
28
|
Requires-Dist: prometheus-api-client (>=0.5.4,<0.6.0)
|
|
28
29
|
Requires-Dist: pytz (>=2023.3,<2024.0)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "krkn-lib"
|
|
3
|
-
version = "5.1.
|
|
3
|
+
version = "5.1.13"
|
|
4
4
|
description = "Foundation library for Kraken"
|
|
5
5
|
authors = ["Red Hat Chaos Team"]
|
|
6
6
|
license = "Apache-2.0"
|
|
@@ -10,7 +10,7 @@ homepage = "https://github.com/redhat-chaos/krkn"
|
|
|
10
10
|
|
|
11
11
|
[tool.poetry.dependencies]
|
|
12
12
|
python = "^3.9"
|
|
13
|
-
kubernetes ="
|
|
13
|
+
kubernetes ="34.1.0"
|
|
14
14
|
sphinxnotes-markdown-builder="^0.5.6"
|
|
15
15
|
requests="^2.29.0"
|
|
16
16
|
kubeconfig = "^1.1.1"
|
|
@@ -27,6 +27,7 @@ cython = "3.0"
|
|
|
27
27
|
numpy= "1.26.4"
|
|
28
28
|
deprecation="2.1.0"
|
|
29
29
|
coverage="^7.6.12"
|
|
30
|
+
importlib-metadata = "^8.7.0"
|
|
30
31
|
|
|
31
32
|
[tool.poetry.group.test.dependencies]
|
|
32
33
|
jinja2 = "^3.1.2"
|
|
@@ -166,7 +166,13 @@ class KrknKubernetes:
|
|
|
166
166
|
|
|
167
167
|
client.Configuration.set_default(self.client_config)
|
|
168
168
|
self.watch_resource = watch.Watch()
|
|
169
|
+
# Get the logger for the kubernetes client
|
|
170
|
+
kubernetes_logger = logging.getLogger("kubernetes")
|
|
169
171
|
|
|
172
|
+
# Set the logging level to a higher level than DEBUG,
|
|
173
|
+
# such as INFO, WARNING, or ERROR
|
|
174
|
+
# This will effectively disable DEBUG level messages.
|
|
175
|
+
kubernetes_logger.setLevel(logging.INFO)
|
|
170
176
|
except OSError:
|
|
171
177
|
raise Exception(
|
|
172
178
|
"Invalid kube-config file: {0}. "
|
|
@@ -528,6 +534,7 @@ class KrknKubernetes:
|
|
|
528
534
|
namespace: str,
|
|
529
535
|
label_selector: str = None,
|
|
530
536
|
field_selector: str = None,
|
|
537
|
+
exclude_label: str = None,
|
|
531
538
|
) -> list[str]:
|
|
532
539
|
"""
|
|
533
540
|
List pods in the given namespace
|
|
@@ -537,6 +544,8 @@ class KrknKubernetes:
|
|
|
537
544
|
(optional default `None`)
|
|
538
545
|
:param field_selector: filter results by config details
|
|
539
546
|
select only running pods by setting "status.phase=Running"
|
|
547
|
+
:param exclude_label: exclude pods matching this label
|
|
548
|
+
in format "key=value" (optional default `None`)
|
|
540
549
|
:return: a list of pod names
|
|
541
550
|
"""
|
|
542
551
|
pods = []
|
|
@@ -552,6 +561,14 @@ class KrknKubernetes:
|
|
|
552
561
|
raise e
|
|
553
562
|
for ret_list in ret:
|
|
554
563
|
for pod in ret_list.items:
|
|
564
|
+
# Skip pods with the exclude label if specified
|
|
565
|
+
if exclude_label and pod.metadata.labels:
|
|
566
|
+
exclude_key, exclude_value = exclude_label.split("=", 1)
|
|
567
|
+
if (
|
|
568
|
+
exclude_key in pod.metadata.labels
|
|
569
|
+
and pod.metadata.labels[exclude_key] == exclude_value
|
|
570
|
+
):
|
|
571
|
+
continue
|
|
555
572
|
pods.append(pod.metadata.name)
|
|
556
573
|
return pods
|
|
557
574
|
|
|
@@ -1371,6 +1388,304 @@ class KrknKubernetes:
|
|
|
1371
1388
|
str(e),
|
|
1372
1389
|
)
|
|
1373
1390
|
|
|
1391
|
+
def get_vm(self, name: str, namespace: str) -> Optional[Dict]:
|
|
1392
|
+
"""
|
|
1393
|
+
Get a Virtual Machine by name and namespace.
|
|
1394
|
+
|
|
1395
|
+
:param name: Name of the VM to retrieve
|
|
1396
|
+
:param namespace: Namespace of the VM
|
|
1397
|
+
:return: The VM object if found, None otherwise
|
|
1398
|
+
"""
|
|
1399
|
+
try:
|
|
1400
|
+
vm = self.custom_object_client.get_namespaced_custom_object(
|
|
1401
|
+
group="kubevirt.io",
|
|
1402
|
+
version="v1",
|
|
1403
|
+
namespace=namespace,
|
|
1404
|
+
plural="virtualmachines",
|
|
1405
|
+
name=name,
|
|
1406
|
+
)
|
|
1407
|
+
return vm
|
|
1408
|
+
except ApiException as e:
|
|
1409
|
+
if e.status == 404:
|
|
1410
|
+
logging.warning(
|
|
1411
|
+
f"VM {name} not found in namespace {namespace}"
|
|
1412
|
+
)
|
|
1413
|
+
return None
|
|
1414
|
+
else:
|
|
1415
|
+
logging.error(f"Error getting VM {name}: {e}")
|
|
1416
|
+
raise
|
|
1417
|
+
except Exception as e:
|
|
1418
|
+
logging.error(f"Unexpected error getting VM {name}: {e}")
|
|
1419
|
+
raise
|
|
1420
|
+
|
|
1421
|
+
def get_vmi(self, name: str, namespace: str) -> Optional[Dict]:
|
|
1422
|
+
"""
|
|
1423
|
+
Get a Virtual Machine Instance by name and namespace.
|
|
1424
|
+
|
|
1425
|
+
:param name: Name of the VMI to retrieve
|
|
1426
|
+
:param namespace: Namespace of the VMI
|
|
1427
|
+
:return: The VMI object if found, None otherwise
|
|
1428
|
+
"""
|
|
1429
|
+
try:
|
|
1430
|
+
vmi = self.custom_object_client.get_namespaced_custom_object(
|
|
1431
|
+
group="kubevirt.io",
|
|
1432
|
+
version="v1",
|
|
1433
|
+
namespace=namespace,
|
|
1434
|
+
plural="virtualmachineinstances",
|
|
1435
|
+
name=name,
|
|
1436
|
+
)
|
|
1437
|
+
return vmi
|
|
1438
|
+
except ApiException as e:
|
|
1439
|
+
if e.status == 404:
|
|
1440
|
+
logging.warning(
|
|
1441
|
+
f"VMI {name} not found in namespace {namespace}"
|
|
1442
|
+
)
|
|
1443
|
+
return None
|
|
1444
|
+
else:
|
|
1445
|
+
logging.error(f"Error getting VMI {name}: {e}")
|
|
1446
|
+
raise
|
|
1447
|
+
except Exception as e:
|
|
1448
|
+
logging.error(f"Unexpected error getting VMI {name}: {e}")
|
|
1449
|
+
raise
|
|
1450
|
+
|
|
1451
|
+
def get_vmis(self, regex_name: str, namespace: str) -> Optional[Dict]:
|
|
1452
|
+
"""
|
|
1453
|
+
Get a Virtual Machine Instance by name and namespace.
|
|
1454
|
+
|
|
1455
|
+
:param name: Name of the VMI to retrieve
|
|
1456
|
+
:param namespace: Namespace of the VMI
|
|
1457
|
+
:return: The VMI object if found, None otherwise
|
|
1458
|
+
"""
|
|
1459
|
+
try:
|
|
1460
|
+
vmis_list = []
|
|
1461
|
+
namespaces = self.list_namespaces_by_regex(namespace)
|
|
1462
|
+
for namespace in namespaces:
|
|
1463
|
+
vmis = self.custom_object_client.list_namespaced_custom_object(
|
|
1464
|
+
group="kubevirt.io",
|
|
1465
|
+
version="v1",
|
|
1466
|
+
namespace=namespace,
|
|
1467
|
+
plural="virtualmachineinstances",
|
|
1468
|
+
)
|
|
1469
|
+
|
|
1470
|
+
for vmi in vmis.get("items"):
|
|
1471
|
+
vmi_name = vmi.get("metadata", {}).get("name")
|
|
1472
|
+
match = re.match(regex_name, vmi_name)
|
|
1473
|
+
if match:
|
|
1474
|
+
vmis_list.append(vmi)
|
|
1475
|
+
except ApiException as e:
|
|
1476
|
+
if e.status == 404:
|
|
1477
|
+
logging.warning(
|
|
1478
|
+
f"VMI {regex_name} not found in namespace {namespace}"
|
|
1479
|
+
)
|
|
1480
|
+
return []
|
|
1481
|
+
else:
|
|
1482
|
+
logging.error(f"Error getting VMI {regex_name}: {e}")
|
|
1483
|
+
raise
|
|
1484
|
+
except Exception as e:
|
|
1485
|
+
logging.error(f"Unexpected error getting VMI {regex_name}: {e}")
|
|
1486
|
+
raise
|
|
1487
|
+
return vmis_list
|
|
1488
|
+
|
|
1489
|
+
def create_vmi(self, name: str, namespace: str, vm_name: str, vmi_body: dict) -> Optional[Dict]:
|
|
1490
|
+
"""
|
|
1491
|
+
Create a Virtual Machine Instance by name and namespace.
|
|
1492
|
+
|
|
1493
|
+
:param name: Name of the VMI to create
|
|
1494
|
+
:param namespace: Namespace of the VMI
|
|
1495
|
+
:param vm_name: Name of the Virtual Machine to create the VMI from
|
|
1496
|
+
:return: The VMI object if created, None otherwise
|
|
1497
|
+
"""
|
|
1498
|
+
try:
|
|
1499
|
+
vmi = self.custom_object_client.create_namespaced_custom_object(
|
|
1500
|
+
group="kubevirt.io",
|
|
1501
|
+
version="v1",
|
|
1502
|
+
namespace=namespace,
|
|
1503
|
+
plural="virtualmachineinstances",
|
|
1504
|
+
name=name,
|
|
1505
|
+
body=vmi_body,
|
|
1506
|
+
)
|
|
1507
|
+
return vmi
|
|
1508
|
+
except ApiException as e:
|
|
1509
|
+
if e.status == 404:
|
|
1510
|
+
logging.warning(f"VMI {name} not found in namespace {namespace}")
|
|
1511
|
+
return None
|
|
1512
|
+
else:
|
|
1513
|
+
logging.error(f"Error creating VMI {name}: {e}")
|
|
1514
|
+
raise
|
|
1515
|
+
except Exception as e:
|
|
1516
|
+
logging.error(f"Unexpected error creating VMI {name}: {e}")
|
|
1517
|
+
raise
|
|
1518
|
+
|
|
1519
|
+
def patch_vm(self, name: str, namespace: str, vm_body: dict) -> Optional[Dict]:
|
|
1520
|
+
"""
|
|
1521
|
+
Patch a Virtual Machine by name and namespace.
|
|
1522
|
+
|
|
1523
|
+
:param name: Name of the VM to patch
|
|
1524
|
+
:param namespace: Namespace of the VM
|
|
1525
|
+
:param vm_body: Body of the VM to patch
|
|
1526
|
+
:return: The VM object if patched, None otherwise
|
|
1527
|
+
"""
|
|
1528
|
+
try:
|
|
1529
|
+
vmi = self.custom_object_client.patch_namespaced_custom_object(
|
|
1530
|
+
group="kubevirt.io",
|
|
1531
|
+
version="v1",
|
|
1532
|
+
namespace=namespace,
|
|
1533
|
+
plural="virtualmachines",
|
|
1534
|
+
name=name,
|
|
1535
|
+
body=vm_body,
|
|
1536
|
+
)
|
|
1537
|
+
return vmi
|
|
1538
|
+
except ApiException as e:
|
|
1539
|
+
if e.status == 404:
|
|
1540
|
+
logging.warning(f"VM {name} not found in namespace {namespace}")
|
|
1541
|
+
return None
|
|
1542
|
+
else:
|
|
1543
|
+
logging.error(f"Error patching VM {name}: {e}")
|
|
1544
|
+
raise
|
|
1545
|
+
except Exception as e:
|
|
1546
|
+
logging.error(f"Unexpected error patching VM {name}: {e}")
|
|
1547
|
+
raise
|
|
1548
|
+
|
|
1549
|
+
def patch_vmi(self, name: str, namespace: str, vmi_body: dict) -> Optional[Dict]:
|
|
1550
|
+
"""
|
|
1551
|
+
Patch a Virtual Machine Instance by name and namespace.
|
|
1552
|
+
|
|
1553
|
+
:param name: Name of the VMI to patch
|
|
1554
|
+
:param namespace: Namespace of the VMI
|
|
1555
|
+
:param vmi_body: Body of the VMI to patch
|
|
1556
|
+
:return: The VMI object if patched, None otherwise
|
|
1557
|
+
"""
|
|
1558
|
+
try:
|
|
1559
|
+
vmi = self.custom_object_client.patch_namespaced_custom_object(
|
|
1560
|
+
group="kubevirt.io",
|
|
1561
|
+
version="v1",
|
|
1562
|
+
namespace=namespace,
|
|
1563
|
+
plural="virtualmachineinstances",
|
|
1564
|
+
name=name,
|
|
1565
|
+
body=vmi_body,
|
|
1566
|
+
)
|
|
1567
|
+
return vmi
|
|
1568
|
+
except ApiException as e:
|
|
1569
|
+
if e.status == 404:
|
|
1570
|
+
logging.warning(f"VMI {name} not found in namespace {namespace}")
|
|
1571
|
+
return None
|
|
1572
|
+
else:
|
|
1573
|
+
logging.error(f"Error patching VMI {name}: {e}")
|
|
1574
|
+
raise
|
|
1575
|
+
except Exception as e:
|
|
1576
|
+
logging.error(f"Unexpected error patching VMI {name}: {e}")
|
|
1577
|
+
raise
|
|
1578
|
+
|
|
1579
|
+
def get_vms(self, regex_name: str, namespace: str) -> Optional[Dict]:
|
|
1580
|
+
"""
|
|
1581
|
+
Get a Virtual Machine by name and namespace.
|
|
1582
|
+
|
|
1583
|
+
:param name: Name of the VM to retrieve
|
|
1584
|
+
:param namespace: Namespace of the VM
|
|
1585
|
+
:return: The VM object if found, None otherwise
|
|
1586
|
+
"""
|
|
1587
|
+
try:
|
|
1588
|
+
vms_list = []
|
|
1589
|
+
namespaces = self.list_namespaces_by_regex(namespace)
|
|
1590
|
+
for namespace in namespaces:
|
|
1591
|
+
vms = self.custom_object_client.list_namespaced_custom_object(
|
|
1592
|
+
group="kubevirt.io",
|
|
1593
|
+
version="v1",
|
|
1594
|
+
namespace=namespace,
|
|
1595
|
+
plural="virtualmachines",
|
|
1596
|
+
)
|
|
1597
|
+
|
|
1598
|
+
for vm in vms.get("items"):
|
|
1599
|
+
vm_name = vm.get("metadata", {}).get("name")
|
|
1600
|
+
match = re.match(regex_name, vm_name)
|
|
1601
|
+
if match:
|
|
1602
|
+
vms_list.append(vm)
|
|
1603
|
+
return vms_list
|
|
1604
|
+
except ApiException as e:
|
|
1605
|
+
if e.status == 404:
|
|
1606
|
+
logging.warning(
|
|
1607
|
+
f"VM {regex_name} not found in namespace {namespace}"
|
|
1608
|
+
)
|
|
1609
|
+
return []
|
|
1610
|
+
else:
|
|
1611
|
+
logging.error(f"Error getting VM {regex_name}: {e}")
|
|
1612
|
+
raise
|
|
1613
|
+
except Exception as e:
|
|
1614
|
+
logging.error(f"Unexpected error getting VM {regex_name}: {e}")
|
|
1615
|
+
raise
|
|
1616
|
+
|
|
1617
|
+
def get_snapshot(self, name: str, namespace: str) -> Optional[Dict]:
|
|
1618
|
+
"""
|
|
1619
|
+
Get a Snapshot by name and namespace.
|
|
1620
|
+
|
|
1621
|
+
:param name: Name of the Snapshot to retrieve
|
|
1622
|
+
:param namespace: Namespace of the Snapshot
|
|
1623
|
+
:return: The Snapshot object if found, None otherwise
|
|
1624
|
+
"""
|
|
1625
|
+
try:
|
|
1626
|
+
vmi = self.custom_object_client.get_namespaced_custom_object(
|
|
1627
|
+
group="kubevirt.io",
|
|
1628
|
+
version="v1",
|
|
1629
|
+
namespace=namespace,
|
|
1630
|
+
plural="VirtualMachineSnapshot",
|
|
1631
|
+
name=name,
|
|
1632
|
+
)
|
|
1633
|
+
return vmi
|
|
1634
|
+
except ApiException as e:
|
|
1635
|
+
if e.status == 404:
|
|
1636
|
+
logging.warning(
|
|
1637
|
+
f"VMI {name} not found in namespace {namespace}"
|
|
1638
|
+
)
|
|
1639
|
+
return None
|
|
1640
|
+
else:
|
|
1641
|
+
logging.error(f"Error getting VMI {name}: {e}")
|
|
1642
|
+
raise
|
|
1643
|
+
except Exception as e:
|
|
1644
|
+
logging.error(f"Unexpected error getting VMI {name}: {e}")
|
|
1645
|
+
raise
|
|
1646
|
+
|
|
1647
|
+
def create_snapshot(
|
|
1648
|
+
self, name: str, namespace: str, vm_name: str
|
|
1649
|
+
) -> Optional[Dict]:
|
|
1650
|
+
"""
|
|
1651
|
+
Create a Snapshot by name and namespace.
|
|
1652
|
+
|
|
1653
|
+
:param name: Name of the Snapshot to create
|
|
1654
|
+
:param namespace: Namespace of the Snapshot
|
|
1655
|
+
:param vm_name: Name of the Virtual Machine to create the Snapshot from
|
|
1656
|
+
:return: The Snapshot object if created, None otherwise
|
|
1657
|
+
"""
|
|
1658
|
+
try:
|
|
1659
|
+
file_loader = PackageLoader("krkn_lib.k8s", "templates")
|
|
1660
|
+
env = Environment(loader=file_loader, autoescape=True)
|
|
1661
|
+
snapshot_template = env.get_template("snapshot.j2")
|
|
1662
|
+
ss_body = yaml.safe_load(
|
|
1663
|
+
snapshot_template.render(
|
|
1664
|
+
name=name, namespace=namespace, vm_name=vm_name
|
|
1665
|
+
)
|
|
1666
|
+
)
|
|
1667
|
+
vmi = self.custom_object_client.create_namespaced_custom_object(
|
|
1668
|
+
group="kubevirt.io",
|
|
1669
|
+
version="v1",
|
|
1670
|
+
namespace=namespace,
|
|
1671
|
+
plural="VirtualMachineSnapshot",
|
|
1672
|
+
name=name,
|
|
1673
|
+
body=ss_body,
|
|
1674
|
+
)
|
|
1675
|
+
return vmi
|
|
1676
|
+
except ApiException as e:
|
|
1677
|
+
if e.status == 404:
|
|
1678
|
+
logging.warning(
|
|
1679
|
+
f"Snapshot {name} not found in namespace {namespace}"
|
|
1680
|
+
)
|
|
1681
|
+
return None
|
|
1682
|
+
else:
|
|
1683
|
+
logging.error(f"Error creating Snapshot {name}: {e}")
|
|
1684
|
+
raise
|
|
1685
|
+
except Exception as e:
|
|
1686
|
+
logging.error(f"Unexpected error creating Snapshot {name}: {e}")
|
|
1687
|
+
raise
|
|
1688
|
+
|
|
1374
1689
|
def get_job_status(
|
|
1375
1690
|
self, name: str, namespace: str = "default"
|
|
1376
1691
|
) -> client.V1Job:
|
|
@@ -1393,6 +1708,82 @@ class KrknKubernetes:
|
|
|
1393
1708
|
)
|
|
1394
1709
|
raise
|
|
1395
1710
|
|
|
1711
|
+
def delete_vm(self, name: str, namespace: str) -> Optional[Dict]:
|
|
1712
|
+
"""
|
|
1713
|
+
Delete a Virtual Machine by name and namespace.
|
|
1714
|
+
|
|
1715
|
+
:param name: Name of the VM to delete
|
|
1716
|
+
:param namespace: Namespace of the VM
|
|
1717
|
+
:return: The VM object if found, None otherwise
|
|
1718
|
+
"""
|
|
1719
|
+
try:
|
|
1720
|
+
return self.custom_object_client.delete_namespaced_custom_object(
|
|
1721
|
+
group="kubevirt.io",
|
|
1722
|
+
version="v1",
|
|
1723
|
+
namespace=namespace,
|
|
1724
|
+
plural="virtualmachines",
|
|
1725
|
+
name=name,
|
|
1726
|
+
)
|
|
1727
|
+
except ApiException as e:
|
|
1728
|
+
if e.status == 404:
|
|
1729
|
+
logging.warning(
|
|
1730
|
+
f"VM {name} not found in namespace {namespace}"
|
|
1731
|
+
)
|
|
1732
|
+
return None
|
|
1733
|
+
else:
|
|
1734
|
+
logging.error(f"Error deleting VM {name}: {e}")
|
|
1735
|
+
raise
|
|
1736
|
+
except Exception as e:
|
|
1737
|
+
logging.error(f"Error deleting VM {name}: {e}")
|
|
1738
|
+
raise
|
|
1739
|
+
|
|
1740
|
+
def delete_vmi(self, vm_name: str, namespace: str):
|
|
1741
|
+
"""
|
|
1742
|
+
Delete a Virtual Machine Instance to simulate a VM outage.
|
|
1743
|
+
|
|
1744
|
+
:param vm_name: Name of the VMI to delete
|
|
1745
|
+
:param namespace: Namespace of the VMI
|
|
1746
|
+
:return: 0 for success, 1 for failure
|
|
1747
|
+
"""
|
|
1748
|
+
logging.info(
|
|
1749
|
+
f"Injecting chaos: Deleting VMI {vm_name} in namespace {namespace}"
|
|
1750
|
+
)
|
|
1751
|
+
try:
|
|
1752
|
+
self.custom_object_client.delete_namespaced_custom_object(
|
|
1753
|
+
group="kubevirt.io",
|
|
1754
|
+
version="v1",
|
|
1755
|
+
namespace=namespace,
|
|
1756
|
+
plural="virtualmachineinstances",
|
|
1757
|
+
name=vm_name,
|
|
1758
|
+
)
|
|
1759
|
+
except ApiException as e:
|
|
1760
|
+
if e.status == 404:
|
|
1761
|
+
logging.warning(f"VMI {vm_name} not found during deletion")
|
|
1762
|
+
return 1
|
|
1763
|
+
else:
|
|
1764
|
+
logging.error(f"API error during VMI deletion: {e}")
|
|
1765
|
+
return 1
|
|
1766
|
+
|
|
1767
|
+
def delete_snapshot(self, snapshot_name: str, namespace: str):
|
|
1768
|
+
"""Helper method to delete any snapshot created by the scenario."""
|
|
1769
|
+
self.logger.info(f"Deleting snapshot '{self.snapshot_name}'...")
|
|
1770
|
+
try:
|
|
1771
|
+
self.custom_object_client.delete_namespaced_custom_object(
|
|
1772
|
+
group="kubevirt.io",
|
|
1773
|
+
version="v1",
|
|
1774
|
+
namespace=namespace,
|
|
1775
|
+
plural="VirtualMachineSnapshot",
|
|
1776
|
+
name=snapshot_name,
|
|
1777
|
+
)
|
|
1778
|
+
self.logger.info(
|
|
1779
|
+
f"Snapshot '{self.snapshot_name}' deleted successfully."
|
|
1780
|
+
)
|
|
1781
|
+
except Exception as e:
|
|
1782
|
+
self.logger.warning(
|
|
1783
|
+
"Failed to delete snapshot, "
|
|
1784
|
+
f"might have been already deleted: {e}"
|
|
1785
|
+
)
|
|
1786
|
+
|
|
1396
1787
|
def monitor_nodes(
|
|
1397
1788
|
self,
|
|
1398
1789
|
) -> (bool, list[str]):
|
|
@@ -3130,3 +3521,36 @@ class KrknKubernetes:
|
|
|
3130
3521
|
pids_list = list(filter(None, pids_list))
|
|
3131
3522
|
return pids_list
|
|
3132
3523
|
return None
|
|
3524
|
+
|
|
3525
|
+
def list_pod_network_interfaces(
|
|
3526
|
+
self, pod_name: str, namespace: str, container_name: str = None
|
|
3527
|
+
) -> list[str]:
|
|
3528
|
+
"""
|
|
3529
|
+
Lists the network interfaces of a pod (Linux only)
|
|
3530
|
+
:param pod_name: the name of the pod
|
|
3531
|
+
:param namespace: the namespaces of the pod
|
|
3532
|
+
:param container_name: the container of the pod where the interfaces
|
|
3533
|
+
will be listed, if None the first will be picked
|
|
3534
|
+
:return: the list of the interfaces
|
|
3535
|
+
"""
|
|
3536
|
+
|
|
3537
|
+
if not self.check_if_pod_exists(pod_name, namespace):
|
|
3538
|
+
raise Exception(
|
|
3539
|
+
f"target pod {pod_name} does not exist in "
|
|
3540
|
+
f"namespace {namespace}"
|
|
3541
|
+
)
|
|
3542
|
+
|
|
3543
|
+
cmd = "ls /sys/class/net"
|
|
3544
|
+
nics_str = self.exec_cmd_in_pod(
|
|
3545
|
+
[cmd],
|
|
3546
|
+
pod_name,
|
|
3547
|
+
namespace,
|
|
3548
|
+
container_name,
|
|
3549
|
+
)
|
|
3550
|
+
nics = nics_str.split("\n")
|
|
3551
|
+
try:
|
|
3552
|
+
nics.remove("lo")
|
|
3553
|
+
nics.remove("")
|
|
3554
|
+
except ValueError:
|
|
3555
|
+
pass
|
|
3556
|
+
return nics
|