krkn-lib 5.1.11__py3-none-any.whl → 6.0.0__py3-none-any.whl
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/aws_tests/__init__.py +1 -1
- krkn_lib/elastic/krkn_elastic.py +3 -1
- krkn_lib/k8s/krkn_kubernetes.py +408 -20
- krkn_lib/k8s/pod_monitor/__init__.py +1 -2
- krkn_lib/k8s/pod_monitor/pod_monitor.py +146 -56
- krkn_lib/k8s/templates/snapshot.j2 +10 -0
- krkn_lib/models/elastic/models.py +24 -1
- krkn_lib/models/k8s/models.py +1 -1
- krkn_lib/models/pod_monitor/models.py +2 -2
- krkn_lib/models/telemetry/models.py +9 -0
- krkn_lib/ocp/krkn_openshift.py +4 -4
- krkn_lib/prometheus/krkn_prometheus.py +1 -1
- krkn_lib/telemetry/k8s/krkn_telemetry_kubernetes.py +1 -1
- krkn_lib/telemetry/ocp/krkn_telemetry_openshift.py +1 -1
- krkn_lib/tests/base_test.py +16 -3
- krkn_lib/tests/test_krkn_elastic_models.py +23 -4
- krkn_lib/tests/test_krkn_kubernetes_check.py +3 -2
- krkn_lib/tests/test_krkn_kubernetes_create.py +5 -3
- krkn_lib/tests/test_krkn_kubernetes_delete.py +3 -2
- krkn_lib/tests/test_krkn_kubernetes_get.py +5 -4
- krkn_lib/tests/test_krkn_kubernetes_misc.py +3 -3
- krkn_lib/tests/test_krkn_kubernetes_models.py +1 -1
- krkn_lib/tests/test_krkn_kubernetes_pods_monitor_models.py +3 -4
- krkn_lib/tests/test_krkn_kubernetes_virt.py +735 -0
- krkn_lib/tests/test_krkn_openshift.py +571 -48
- krkn_lib/tests/test_krkn_telemetry_kubernetes.py +848 -0
- krkn_lib/tests/test_safe_logger.py +496 -0
- krkn_lib/tests/test_utils.py +4 -5
- krkn_lib/utils/functions.py +4 -3
- krkn_lib/version/version.py +5 -2
- {krkn_lib-5.1.11.dist-info → krkn_lib-6.0.0.dist-info}/METADATA +5 -8
- {krkn_lib-5.1.11.dist-info → krkn_lib-6.0.0.dist-info}/RECORD +34 -30
- {krkn_lib-5.1.11.dist-info → krkn_lib-6.0.0.dist-info}/WHEEL +1 -1
- {krkn_lib-5.1.11.dist-info/licenses → krkn_lib-6.0.0.dist-info}/LICENSE +0 -0
krkn_lib/aws_tests/__init__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
from ..tests.base_test import * # NOQA
|
|
1
|
+
from ..tests.base_test import * # NOQA
|
krkn_lib/elastic/krkn_elastic.py
CHANGED
|
@@ -53,7 +53,9 @@ class KrknElastic:
|
|
|
53
53
|
ssl_show_warn=False,
|
|
54
54
|
)
|
|
55
55
|
except Exception as e:
|
|
56
|
-
self.safe_logger.error(
|
|
56
|
+
self.safe_logger.error(
|
|
57
|
+
"Failed to initialize elasticsearch: %s" % e
|
|
58
|
+
)
|
|
57
59
|
raise e
|
|
58
60
|
|
|
59
61
|
def upload_data_to_elasticsearch(self, item: dict, index: str = "") -> int:
|
krkn_lib/k8s/krkn_kubernetes.py
CHANGED
|
@@ -159,17 +159,23 @@ class KrknKubernetes:
|
|
|
159
159
|
os.environ["HTTP_PROXY"] = http_proxy
|
|
160
160
|
self.client_config.proxy = http_proxy
|
|
161
161
|
proxy_auth = urlparse(http_proxy)
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
)
|
|
162
|
+
if (
|
|
163
|
+
proxy_auth.username is not None
|
|
164
|
+
and proxy_auth.password is not None
|
|
165
|
+
):
|
|
166
|
+
auth_string = (
|
|
167
|
+
proxy_auth.username + ":" + proxy_auth.password
|
|
168
|
+
)
|
|
169
|
+
self.client_config.proxy_headers = (
|
|
170
|
+
urllib3.util.make_headers(proxy_basic_auth=auth_string)
|
|
171
|
+
)
|
|
166
172
|
|
|
167
173
|
client.Configuration.set_default(self.client_config)
|
|
168
174
|
self.watch_resource = watch.Watch()
|
|
169
175
|
# Get the logger for the kubernetes client
|
|
170
|
-
kubernetes_logger = logging.getLogger(
|
|
176
|
+
kubernetes_logger = logging.getLogger("kubernetes")
|
|
171
177
|
|
|
172
|
-
# Set the logging level to a higher level than DEBUG,
|
|
178
|
+
# Set the logging level to a higher level than DEBUG,
|
|
173
179
|
# such as INFO, WARNING, or ERROR
|
|
174
180
|
# This will effectively disable DEBUG level messages.
|
|
175
181
|
kubernetes_logger.setLevel(logging.INFO)
|
|
@@ -185,7 +191,7 @@ class KrknKubernetes:
|
|
|
185
191
|
on other distributions
|
|
186
192
|
|
|
187
193
|
*** IT MUST BE CONSIDERED A PRIVATE METHOD (CANNOT USE
|
|
188
|
-
*** DOUBLE UNDERSCORE TO
|
|
194
|
+
*** DOUBLE UNDERSCORE TO MAINTAIN IT VISIBLE ON SUB-CLASSES)
|
|
189
195
|
*** USED IN KrknKubernetes and KrknOpenshift TO AUTODETECT
|
|
190
196
|
*** THE CLUSTER TYPE
|
|
191
197
|
|
|
@@ -237,7 +243,10 @@ class KrknKubernetes:
|
|
|
237
243
|
minor_version = api_response.minor
|
|
238
244
|
return major_version + "." + minor_version
|
|
239
245
|
except ApiException as e:
|
|
240
|
-
|
|
246
|
+
logging.error(
|
|
247
|
+
"Exception when calling VersionApi->get_code: %s", str(e)
|
|
248
|
+
)
|
|
249
|
+
raise e
|
|
241
250
|
|
|
242
251
|
def get_host(self) -> str:
|
|
243
252
|
"""
|
|
@@ -874,7 +883,7 @@ class KrknKubernetes:
|
|
|
874
883
|
services.append(serv.metadata.name)
|
|
875
884
|
return services
|
|
876
885
|
|
|
877
|
-
# Outputs a json blob with
|
|
886
|
+
# Outputs a json blob with information about all pods in a given namespace
|
|
878
887
|
def get_all_pod_info(
|
|
879
888
|
self,
|
|
880
889
|
namespace: str = "default",
|
|
@@ -978,7 +987,7 @@ class KrknKubernetes:
|
|
|
978
987
|
:param command: command parameters list or full command string
|
|
979
988
|
if the command must be piped to `bash -c`
|
|
980
989
|
(in that case `base_command` parameter
|
|
981
|
-
must
|
|
990
|
+
must be omitted`)
|
|
982
991
|
:param pod_name: pod where the command must be executed
|
|
983
992
|
:param namespace: namespace of the pod
|
|
984
993
|
:param container: container where the command
|
|
@@ -1038,7 +1047,7 @@ class KrknKubernetes:
|
|
|
1038
1047
|
:param command: command parameters list or full command string
|
|
1039
1048
|
if the command must be piped to `bash -c`
|
|
1040
1049
|
(in that case `base_command` parameter
|
|
1041
|
-
must
|
|
1050
|
+
must be omitted`)
|
|
1042
1051
|
:param pod_name: pod where the command must be executed
|
|
1043
1052
|
:param namespace: namespace of the pod
|
|
1044
1053
|
:param container: container where the command
|
|
@@ -1093,7 +1102,7 @@ class KrknKubernetes:
|
|
|
1093
1102
|
)
|
|
1094
1103
|
except Exception as e:
|
|
1095
1104
|
raise e
|
|
1096
|
-
# apparently stream API doesn't
|
|
1105
|
+
# apparently stream API doesn't raise an Exception
|
|
1097
1106
|
# if the command fails to be executed
|
|
1098
1107
|
|
|
1099
1108
|
if "OCI runtime exec failed" in ret:
|
|
@@ -1388,6 +1397,311 @@ class KrknKubernetes:
|
|
|
1388
1397
|
str(e),
|
|
1389
1398
|
)
|
|
1390
1399
|
|
|
1400
|
+
def get_vm(self, name: str, namespace: str) -> Optional[Dict]:
|
|
1401
|
+
"""
|
|
1402
|
+
Get a Virtual Machine by name and namespace.
|
|
1403
|
+
|
|
1404
|
+
:param name: Name of the VM to retrieve
|
|
1405
|
+
:param namespace: Namespace of the VM
|
|
1406
|
+
:return: The VM object if found, None otherwise
|
|
1407
|
+
"""
|
|
1408
|
+
try:
|
|
1409
|
+
vm = self.custom_object_client.get_namespaced_custom_object(
|
|
1410
|
+
group="kubevirt.io",
|
|
1411
|
+
version="v1",
|
|
1412
|
+
namespace=namespace,
|
|
1413
|
+
plural="virtualmachines",
|
|
1414
|
+
name=name,
|
|
1415
|
+
)
|
|
1416
|
+
return vm
|
|
1417
|
+
except ApiException as e:
|
|
1418
|
+
if e.status == 404:
|
|
1419
|
+
logging.warning(
|
|
1420
|
+
f"VM {name} not found in namespace {namespace}"
|
|
1421
|
+
)
|
|
1422
|
+
return None
|
|
1423
|
+
else:
|
|
1424
|
+
logging.error(f"Error getting VM {name}: {e}")
|
|
1425
|
+
raise
|
|
1426
|
+
except Exception as e:
|
|
1427
|
+
logging.error(f"Unexpected error getting VM {name}: {e}")
|
|
1428
|
+
raise
|
|
1429
|
+
|
|
1430
|
+
def get_vmi(self, name: str, namespace: str) -> Optional[Dict]:
|
|
1431
|
+
"""
|
|
1432
|
+
Get a Virtual Machine Instance by name and namespace.
|
|
1433
|
+
|
|
1434
|
+
:param name: Name of the VMI to retrieve
|
|
1435
|
+
:param namespace: Namespace of the VMI
|
|
1436
|
+
:return: The VMI object if found, None otherwise
|
|
1437
|
+
"""
|
|
1438
|
+
try:
|
|
1439
|
+
vmi = self.custom_object_client.get_namespaced_custom_object(
|
|
1440
|
+
group="kubevirt.io",
|
|
1441
|
+
version="v1",
|
|
1442
|
+
namespace=namespace,
|
|
1443
|
+
plural="virtualmachineinstances",
|
|
1444
|
+
name=name,
|
|
1445
|
+
)
|
|
1446
|
+
return vmi
|
|
1447
|
+
except ApiException as e:
|
|
1448
|
+
if e.status == 404:
|
|
1449
|
+
logging.warning(
|
|
1450
|
+
f"VMI {name} not found in namespace {namespace}"
|
|
1451
|
+
)
|
|
1452
|
+
return None
|
|
1453
|
+
else:
|
|
1454
|
+
logging.error(f"Error getting VMI {name}: {e}")
|
|
1455
|
+
raise
|
|
1456
|
+
except Exception as e:
|
|
1457
|
+
logging.error(f"Unexpected error getting VMI {name}: {e}")
|
|
1458
|
+
raise
|
|
1459
|
+
|
|
1460
|
+
def get_vmis(self, regex_name: str, namespace: str) -> Optional[Dict]:
|
|
1461
|
+
"""
|
|
1462
|
+
Get a Virtual Machine Instance by name and namespace.
|
|
1463
|
+
|
|
1464
|
+
:param name: Name of the VMI to retrieve
|
|
1465
|
+
:param namespace: Namespace of the VMI
|
|
1466
|
+
:return: The VMI object if found, None otherwise
|
|
1467
|
+
"""
|
|
1468
|
+
try:
|
|
1469
|
+
vmis_list = []
|
|
1470
|
+
namespaces = self.list_namespaces_by_regex(namespace)
|
|
1471
|
+
for namespace in namespaces:
|
|
1472
|
+
vmis = self.custom_object_client.list_namespaced_custom_object(
|
|
1473
|
+
group="kubevirt.io",
|
|
1474
|
+
version="v1",
|
|
1475
|
+
namespace=namespace,
|
|
1476
|
+
plural="virtualmachineinstances",
|
|
1477
|
+
)
|
|
1478
|
+
|
|
1479
|
+
for vmi in vmis.get("items"):
|
|
1480
|
+
vmi_name = vmi.get("metadata", {}).get("name")
|
|
1481
|
+
match = re.match(regex_name, vmi_name)
|
|
1482
|
+
if match:
|
|
1483
|
+
vmis_list.append(vmi)
|
|
1484
|
+
except ApiException as e:
|
|
1485
|
+
if e.status == 404:
|
|
1486
|
+
logging.warning(
|
|
1487
|
+
f"VMI {regex_name} not found in namespace {namespace}"
|
|
1488
|
+
)
|
|
1489
|
+
return []
|
|
1490
|
+
else:
|
|
1491
|
+
logging.error(f"Error getting VMI {regex_name}: {e}")
|
|
1492
|
+
raise
|
|
1493
|
+
except Exception as e:
|
|
1494
|
+
logging.error(f"Unexpected error getting VMI {regex_name}: {e}")
|
|
1495
|
+
raise
|
|
1496
|
+
return vmis_list
|
|
1497
|
+
|
|
1498
|
+
def create_vmi(
|
|
1499
|
+
self, name: str, namespace: str, vm_name: str, vmi_body: dict
|
|
1500
|
+
) -> Optional[Dict]:
|
|
1501
|
+
"""
|
|
1502
|
+
Create a Virtual Machine Instance by name and namespace.
|
|
1503
|
+
|
|
1504
|
+
:param name: Name of the VMI to create
|
|
1505
|
+
:param namespace: Namespace of the VMI
|
|
1506
|
+
:param vm_name: Name of the Virtual Machine to create the VMI from
|
|
1507
|
+
:return: The VMI object if created, None otherwise
|
|
1508
|
+
"""
|
|
1509
|
+
try:
|
|
1510
|
+
vmi = self.custom_object_client.create_namespaced_custom_object(
|
|
1511
|
+
group="kubevirt.io",
|
|
1512
|
+
version="v1",
|
|
1513
|
+
namespace=namespace,
|
|
1514
|
+
plural="virtualmachineinstances",
|
|
1515
|
+
body=vmi_body,
|
|
1516
|
+
)
|
|
1517
|
+
return vmi
|
|
1518
|
+
except ApiException as e:
|
|
1519
|
+
if e.status == 404:
|
|
1520
|
+
logging.warning(
|
|
1521
|
+
f"VMI {name} not found in namespace {namespace}"
|
|
1522
|
+
)
|
|
1523
|
+
return None
|
|
1524
|
+
else:
|
|
1525
|
+
logging.error(f"Error creating VMI {name}: {e}")
|
|
1526
|
+
raise
|
|
1527
|
+
except Exception as e:
|
|
1528
|
+
logging.error(f"Unexpected error creating VMI {name}: {e}")
|
|
1529
|
+
raise
|
|
1530
|
+
|
|
1531
|
+
def patch_vm(
|
|
1532
|
+
self, name: str, namespace: str, vm_body: dict
|
|
1533
|
+
) -> Optional[Dict]:
|
|
1534
|
+
"""
|
|
1535
|
+
Patch a Virtual Machine by name and namespace.
|
|
1536
|
+
|
|
1537
|
+
:param name: Name of the VM to patch
|
|
1538
|
+
:param namespace: Namespace of the VM
|
|
1539
|
+
:param vm_body: Body of the VM to patch
|
|
1540
|
+
:return: The VM object if patched, None otherwise
|
|
1541
|
+
"""
|
|
1542
|
+
try:
|
|
1543
|
+
vmi = self.custom_object_client.patch_namespaced_custom_object(
|
|
1544
|
+
group="kubevirt.io",
|
|
1545
|
+
version="v1",
|
|
1546
|
+
namespace=namespace,
|
|
1547
|
+
plural="virtualmachines",
|
|
1548
|
+
name=name,
|
|
1549
|
+
body=vm_body,
|
|
1550
|
+
)
|
|
1551
|
+
return vmi
|
|
1552
|
+
except ApiException as e:
|
|
1553
|
+
if e.status == 404:
|
|
1554
|
+
logging.warning(
|
|
1555
|
+
f"VM {name} not found in namespace {namespace}"
|
|
1556
|
+
)
|
|
1557
|
+
return None
|
|
1558
|
+
else:
|
|
1559
|
+
logging.error(f"Error patching VM {name}: {e}")
|
|
1560
|
+
raise
|
|
1561
|
+
except Exception as e:
|
|
1562
|
+
logging.error(f"Unexpected error patching VM {name}: {e}")
|
|
1563
|
+
raise
|
|
1564
|
+
|
|
1565
|
+
def patch_vmi(
|
|
1566
|
+
self, name: str, namespace: str, vmi_body: dict
|
|
1567
|
+
) -> Optional[Dict]:
|
|
1568
|
+
"""
|
|
1569
|
+
Patch a Virtual Machine Instance by name and namespace.
|
|
1570
|
+
|
|
1571
|
+
:param name: Name of the VMI to patch
|
|
1572
|
+
:param namespace: Namespace of the VMI
|
|
1573
|
+
:param vmi_body: Body of the VMI to patch
|
|
1574
|
+
:return: The VMI object if patched, None otherwise
|
|
1575
|
+
"""
|
|
1576
|
+
try:
|
|
1577
|
+
vmi = self.custom_object_client.patch_namespaced_custom_object(
|
|
1578
|
+
group="kubevirt.io",
|
|
1579
|
+
version="v1",
|
|
1580
|
+
namespace=namespace,
|
|
1581
|
+
plural="virtualmachineinstances",
|
|
1582
|
+
name=name,
|
|
1583
|
+
body=vmi_body,
|
|
1584
|
+
)
|
|
1585
|
+
return vmi
|
|
1586
|
+
except ApiException as e:
|
|
1587
|
+
if e.status == 404:
|
|
1588
|
+
logging.warning(
|
|
1589
|
+
f"VMI {name} not found in namespace {namespace}"
|
|
1590
|
+
)
|
|
1591
|
+
return None
|
|
1592
|
+
else:
|
|
1593
|
+
logging.error(f"Error patching VMI {name}: {e}")
|
|
1594
|
+
raise
|
|
1595
|
+
except Exception as e:
|
|
1596
|
+
logging.error(f"Unexpected error patching VMI {name}: {e}")
|
|
1597
|
+
raise
|
|
1598
|
+
|
|
1599
|
+
def get_vms(self, regex_name: str, namespace: str) -> Optional[Dict]:
|
|
1600
|
+
"""
|
|
1601
|
+
Get a Virtual Machine by name and namespace.
|
|
1602
|
+
|
|
1603
|
+
:param name: Name of the VM to retrieve
|
|
1604
|
+
:param namespace: Namespace of the VM
|
|
1605
|
+
:return: The VM object if found, None otherwise
|
|
1606
|
+
"""
|
|
1607
|
+
try:
|
|
1608
|
+
vms_list = []
|
|
1609
|
+
namespaces = self.list_namespaces_by_regex(namespace)
|
|
1610
|
+
for namespace in namespaces:
|
|
1611
|
+
vms = self.custom_object_client.list_namespaced_custom_object(
|
|
1612
|
+
group="kubevirt.io",
|
|
1613
|
+
version="v1",
|
|
1614
|
+
namespace=namespace,
|
|
1615
|
+
plural="virtualmachines",
|
|
1616
|
+
)
|
|
1617
|
+
|
|
1618
|
+
for vm in vms.get("items"):
|
|
1619
|
+
vm_name = vm.get("metadata", {}).get("name")
|
|
1620
|
+
match = re.match(regex_name, vm_name)
|
|
1621
|
+
if match:
|
|
1622
|
+
vms_list.append(vm)
|
|
1623
|
+
return vms_list
|
|
1624
|
+
except ApiException as e:
|
|
1625
|
+
if e.status == 404:
|
|
1626
|
+
logging.warning(
|
|
1627
|
+
f"VM {regex_name} not found in namespace {namespace}"
|
|
1628
|
+
)
|
|
1629
|
+
return []
|
|
1630
|
+
else:
|
|
1631
|
+
logging.error(f"Error getting VM {regex_name}: {e}")
|
|
1632
|
+
raise
|
|
1633
|
+
except Exception as e:
|
|
1634
|
+
logging.error(f"Unexpected error getting VM {regex_name}: {e}")
|
|
1635
|
+
raise
|
|
1636
|
+
|
|
1637
|
+
def get_snapshot(self, name: str, namespace: str) -> Optional[Dict]:
|
|
1638
|
+
"""
|
|
1639
|
+
Get a Snapshot by name and namespace.
|
|
1640
|
+
|
|
1641
|
+
:param name: Name of the Snapshot to retrieve
|
|
1642
|
+
:param namespace: Namespace of the Snapshot
|
|
1643
|
+
:return: The Snapshot object if found, None otherwise
|
|
1644
|
+
"""
|
|
1645
|
+
try:
|
|
1646
|
+
snapshot = self.custom_object_client.get_namespaced_custom_object(
|
|
1647
|
+
group="snapshot.kubevirt.io",
|
|
1648
|
+
version="v1beta1",
|
|
1649
|
+
namespace=namespace,
|
|
1650
|
+
plural="virtualmachinesnapshots",
|
|
1651
|
+
name=name,
|
|
1652
|
+
)
|
|
1653
|
+
return snapshot
|
|
1654
|
+
except ApiException as e:
|
|
1655
|
+
if e.status == 404:
|
|
1656
|
+
logging.warning(
|
|
1657
|
+
f"SnapShot {name} not found in namespace {namespace}"
|
|
1658
|
+
)
|
|
1659
|
+
return None
|
|
1660
|
+
else:
|
|
1661
|
+
logging.error(f"Error getting snapshot {name}: {e}")
|
|
1662
|
+
raise
|
|
1663
|
+
except Exception as e:
|
|
1664
|
+
logging.error(f"Unexpected error getting snapshot {name}: {e}")
|
|
1665
|
+
raise
|
|
1666
|
+
|
|
1667
|
+
def create_snapshot(
|
|
1668
|
+
self, name: str, namespace: str, vm_name: str
|
|
1669
|
+
) -> Optional[Dict]:
|
|
1670
|
+
"""
|
|
1671
|
+
Create a Snapshot by name and namespace.
|
|
1672
|
+
|
|
1673
|
+
:param name: Name of the Snapshot to create
|
|
1674
|
+
:param namespace: Namespace of the Snapshot
|
|
1675
|
+
:param vm_name: Name of the Virtual Machine to create the Snapshot from
|
|
1676
|
+
:return: The Snapshot object if created, None otherwise
|
|
1677
|
+
"""
|
|
1678
|
+
try:
|
|
1679
|
+
file_loader = PackageLoader("krkn_lib.k8s", "templates")
|
|
1680
|
+
env = Environment(loader=file_loader, autoescape=True)
|
|
1681
|
+
snapshot_template = env.get_template("snapshot.j2")
|
|
1682
|
+
ss_body = yaml.safe_load(
|
|
1683
|
+
snapshot_template.render(
|
|
1684
|
+
name=name, namespace=namespace, vm_name=vm_name
|
|
1685
|
+
)
|
|
1686
|
+
)
|
|
1687
|
+
snapshot = (
|
|
1688
|
+
self.custom_object_client.create_namespaced_custom_object(
|
|
1689
|
+
group="snapshot.kubevirt.io",
|
|
1690
|
+
version="v1beta1",
|
|
1691
|
+
namespace=namespace,
|
|
1692
|
+
plural="virtualmachinesnapshots",
|
|
1693
|
+
body=ss_body,
|
|
1694
|
+
)
|
|
1695
|
+
)
|
|
1696
|
+
return snapshot
|
|
1697
|
+
except ApiException as e:
|
|
1698
|
+
|
|
1699
|
+
logging.error(f"Error creating Snapshot {name}: {e}")
|
|
1700
|
+
raise
|
|
1701
|
+
except Exception as e:
|
|
1702
|
+
logging.error(f"Unexpected error creating Snapshot {name}: {e}")
|
|
1703
|
+
raise
|
|
1704
|
+
|
|
1391
1705
|
def get_job_status(
|
|
1392
1706
|
self, name: str, namespace: str = "default"
|
|
1393
1707
|
) -> client.V1Job:
|
|
@@ -1410,6 +1724,80 @@ class KrknKubernetes:
|
|
|
1410
1724
|
)
|
|
1411
1725
|
raise
|
|
1412
1726
|
|
|
1727
|
+
def delete_vm(self, name: str, namespace: str) -> Optional[Dict]:
|
|
1728
|
+
"""
|
|
1729
|
+
Delete a Virtual Machine by name and namespace.
|
|
1730
|
+
|
|
1731
|
+
:param name: Name of the VM to delete
|
|
1732
|
+
:param namespace: Namespace of the VM
|
|
1733
|
+
:return: The VM object if found, None otherwise
|
|
1734
|
+
"""
|
|
1735
|
+
try:
|
|
1736
|
+
return self.custom_object_client.delete_namespaced_custom_object(
|
|
1737
|
+
group="kubevirt.io",
|
|
1738
|
+
version="v1",
|
|
1739
|
+
namespace=namespace,
|
|
1740
|
+
plural="virtualmachines",
|
|
1741
|
+
name=name,
|
|
1742
|
+
)
|
|
1743
|
+
except ApiException as e:
|
|
1744
|
+
if e.status == 404:
|
|
1745
|
+
logging.warning(
|
|
1746
|
+
f"VM {name} not found in namespace {namespace}"
|
|
1747
|
+
)
|
|
1748
|
+
return None
|
|
1749
|
+
else:
|
|
1750
|
+
logging.error(f"Error deleting VM {name}: {e}")
|
|
1751
|
+
raise
|
|
1752
|
+
except Exception as e:
|
|
1753
|
+
logging.error(f"Error deleting VM {name}: {e}")
|
|
1754
|
+
raise
|
|
1755
|
+
|
|
1756
|
+
def delete_vmi(self, vm_name: str, namespace: str):
|
|
1757
|
+
"""
|
|
1758
|
+
Delete a Virtual Machine Instance to simulate a VM outage.
|
|
1759
|
+
|
|
1760
|
+
:param vm_name: Name of the VMI to delete
|
|
1761
|
+
:param namespace: Namespace of the VMI
|
|
1762
|
+
:return: 0 for success, 1 for failure
|
|
1763
|
+
"""
|
|
1764
|
+
logging.info(
|
|
1765
|
+
f"Injecting chaos: Deleting VMI {vm_name} in namespace {namespace}"
|
|
1766
|
+
)
|
|
1767
|
+
try:
|
|
1768
|
+
self.custom_object_client.delete_namespaced_custom_object(
|
|
1769
|
+
group="kubevirt.io",
|
|
1770
|
+
version="v1",
|
|
1771
|
+
namespace=namespace,
|
|
1772
|
+
plural="virtualmachineinstances",
|
|
1773
|
+
name=vm_name,
|
|
1774
|
+
)
|
|
1775
|
+
except ApiException as e:
|
|
1776
|
+
if e.status == 404:
|
|
1777
|
+
logging.warning(f"VMI {vm_name} not found during deletion")
|
|
1778
|
+
return 1
|
|
1779
|
+
else:
|
|
1780
|
+
logging.error(f"API error during VMI deletion: {e}")
|
|
1781
|
+
return 1
|
|
1782
|
+
|
|
1783
|
+
def delete_snapshot(self, snapshot_name: str, namespace: str):
|
|
1784
|
+
"""Helper method to delete any snapshot created by the scenario."""
|
|
1785
|
+
logging.info(f"Deleting snapshot '{snapshot_name}'...")
|
|
1786
|
+
try:
|
|
1787
|
+
self.custom_object_client.delete_namespaced_custom_object(
|
|
1788
|
+
group="snapshot.kubevirt.io",
|
|
1789
|
+
version="v1beta1",
|
|
1790
|
+
namespace=namespace,
|
|
1791
|
+
plural="virtualmachinesnapshots",
|
|
1792
|
+
name=snapshot_name,
|
|
1793
|
+
)
|
|
1794
|
+
logging.info(f"Snapshot '{snapshot_name}' deleted successfully.")
|
|
1795
|
+
except Exception as e:
|
|
1796
|
+
logging.warning(
|
|
1797
|
+
"Failed to delete snapshot, "
|
|
1798
|
+
f"might have been already deleted: {e}"
|
|
1799
|
+
)
|
|
1800
|
+
|
|
1413
1801
|
def monitor_nodes(
|
|
1414
1802
|
self,
|
|
1415
1803
|
) -> (bool, list[str]):
|
|
@@ -1432,6 +1820,7 @@ class KrknKubernetes:
|
|
|
1432
1820
|
str(e),
|
|
1433
1821
|
)
|
|
1434
1822
|
raise e
|
|
1823
|
+
node_ready_status = "False"
|
|
1435
1824
|
for condition in node_info.status.conditions:
|
|
1436
1825
|
if condition.type == "KernelDeadlock":
|
|
1437
1826
|
node_kerneldeadlock_status = condition.status
|
|
@@ -2005,7 +2394,7 @@ class KrknKubernetes:
|
|
|
2005
2394
|
)
|
|
2006
2395
|
|
|
2007
2396
|
path = f"/api/{api_version}/{resource.name}"
|
|
2008
|
-
|
|
2397
|
+
data = self.api_client.call_api(
|
|
2009
2398
|
path,
|
|
2010
2399
|
"GET",
|
|
2011
2400
|
path_params,
|
|
@@ -2168,7 +2557,6 @@ class KrknKubernetes:
|
|
|
2168
2557
|
else:
|
|
2169
2558
|
node_info.nodes_type = "unknown"
|
|
2170
2559
|
|
|
2171
|
-
node_info.architecture = node.status.node_info.architecture
|
|
2172
2560
|
node_info.architecture = node.status.node_info.architecture
|
|
2173
2561
|
node_info.kernel_version = node.status.node_info.kernel_version
|
|
2174
2562
|
node_info.kubelet_version = (
|
|
@@ -2255,7 +2643,7 @@ class KrknKubernetes:
|
|
|
2255
2643
|
sequential number of the archive assigned to the worker
|
|
2256
2644
|
and the extension tar.b64
|
|
2257
2645
|
:param queue: the queue from which the sequential
|
|
2258
|
-
number
|
|
2646
|
+
number will be popped
|
|
2259
2647
|
:param queue_size: total size of the queue
|
|
2260
2648
|
:param downloaded_file_list: the list of
|
|
2261
2649
|
archive number and local filename downloaded
|
|
@@ -2377,7 +2765,7 @@ class KrknKubernetes:
|
|
|
2377
2765
|
where the temporary archive
|
|
2378
2766
|
will be stored (will be deleted once the download
|
|
2379
2767
|
terminates, must be writable
|
|
2380
|
-
and must have enough space to
|
|
2768
|
+
and must have enough space to temporarily store the archive)
|
|
2381
2769
|
:param target_path: the path that will be archived
|
|
2382
2770
|
and downloaded from the container
|
|
2383
2771
|
:param archive_files_prefix: prefix string that will be added
|
|
@@ -2640,7 +3028,7 @@ class KrknKubernetes:
|
|
|
2640
3028
|
["application/json"]
|
|
2641
3029
|
)
|
|
2642
3030
|
try:
|
|
2643
|
-
|
|
3031
|
+
data = self.api_client.call_api(
|
|
2644
3032
|
path,
|
|
2645
3033
|
"POST",
|
|
2646
3034
|
path_params,
|
|
@@ -2881,7 +3269,7 @@ class KrknKubernetes:
|
|
|
2881
3269
|
default 5000
|
|
2882
3270
|
:param port_name: the port name if the Service is pointing to
|
|
2883
3271
|
a string name instead of a port number
|
|
2884
|
-
:param stats_route: overrides the
|
|
3272
|
+
:param stats_route: overrides the default route where the stats
|
|
2885
3273
|
action will be mapped, change it only if you have a /stats
|
|
2886
3274
|
route in your test_plan
|
|
2887
3275
|
:return: a structure containing all the infos of the
|
|
@@ -2946,7 +3334,7 @@ class KrknKubernetes:
|
|
|
2946
3334
|
|
|
2947
3335
|
def service_exists(self, service_name: str, namespace: str) -> bool:
|
|
2948
3336
|
"""
|
|
2949
|
-
Checks
|
|
3337
|
+
Checks whether a kubernetes Service exist or not
|
|
2950
3338
|
:param service_name: the name of the service to check
|
|
2951
3339
|
:param namespace: the namespace where the service should exist
|
|
2952
3340
|
:return: True if the service exists, False if not
|
|
@@ -3059,7 +3447,7 @@ class KrknKubernetes:
|
|
|
3059
3447
|
["application/json"]
|
|
3060
3448
|
)
|
|
3061
3449
|
path = f"/api/v1/nodes/{node_name}/proxy/stats/summary"
|
|
3062
|
-
|
|
3450
|
+
data = self.api_client.call_api(
|
|
3063
3451
|
path,
|
|
3064
3452
|
"GET",
|
|
3065
3453
|
path_params,
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
from .pod_monitor import (
|
|
2
2
|
select_and_monitor_by_label,
|
|
3
|
-
select_and_monitor_by_namespace_pattern_and_label,
|
|
4
3
|
select_and_monitor_by_name_pattern_and_namespace_pattern,
|
|
4
|
+
select_and_monitor_by_namespace_pattern_and_label,
|
|
5
5
|
)
|
|
6
6
|
|
|
7
|
-
|
|
8
7
|
__all__ = [
|
|
9
8
|
"select_and_monitor_by_label",
|
|
10
9
|
"select_and_monitor_by_namespace_pattern_and_label",
|