diff --git a/src/krkn_lib/elastic/krkn_elastic.py b/src/krkn_lib/elastic/krkn_elastic.py index a5771103..a3c939f1 100644 --- a/src/krkn_lib/elastic/krkn_elastic.py +++ b/src/krkn_lib/elastic/krkn_elastic.py @@ -2,17 +2,17 @@ import datetime import logging +import math import time -import math import urllib3 from elasticsearch import Elasticsearch, NotFoundError from elasticsearch_dsl import Search from krkn_lib.models.elastic.models import ( ElasticAlert, - ElasticMetric, ElasticChaosRunTelemetry, + ElasticMetric, ) from krkn_lib.models.telemetry import ChaosRunTelemetry from krkn_lib.utils.safe_logger import SafeLogger diff --git a/src/krkn_lib/k8s/krkn_kubernetes.py b/src/krkn_lib/k8s/krkn_kubernetes.py index 36223755..a90b4338 100644 --- a/src/krkn_lib/k8s/krkn_kubernetes.py +++ b/src/krkn_lib/k8s/krkn_kubernetes.py @@ -12,6 +12,7 @@ from functools import partial from queue import Queue from typing import Any, Dict, List, Optional +from urllib.parse import urlparse import arcaflow_lib_kubernetes import kubernetes @@ -37,7 +38,7 @@ Volume, VolumeMount, ) -from krkn_lib.models.telemetry import NodeInfo, Taint, ClusterEvent +from krkn_lib.models.telemetry import ClusterEvent, NodeInfo, Taint from krkn_lib.utils import filter_dictionary, get_random_string from krkn_lib.utils.safe_logger import SafeLogger @@ -144,20 +145,42 @@ def __initialize_clients(self, kubeconfig_path: str = None): conf.use_context("krkn-context") try: - config.load_kube_config(kubeconfig_path) - self.api_client = client.ApiClient() - self.k8s_client = config.new_client_from_config( - config_file=kubeconfig_path - ) - self.cli = client.CoreV1Api(self.k8s_client) + # config.load_kube_config(kubeconfig_path) + + client_config = client.Configuration() + http_proxy = os.getenv("http_proxy", None) + if http_proxy and "@" in http_proxy: + proxy_auth = urlparse(http_proxy) + auth_string = proxy_auth.username + ":" + proxy_auth.password + client_config.username = proxy_auth.username + client_config.password = proxy_auth.password + config.load_kube_config( + kubeconfig_path, + persist_config=True, + client_configuration=client_config, + ) + + proxy_url = http_proxy + if proxy_url: + client_config.proxy = proxy_url + if proxy_auth: + client_config.proxy_headers = urllib3.util.make_headers( + proxy_basic_auth=auth_string + ) + + client.Configuration.set_default(client_config) + + self.api_client = client.ApiClient(client_config) + + self.cli = client.CoreV1Api(self.api_client) self.version_client = client.VersionApi(self.api_client) self.apps_api = client.AppsV1Api(self.api_client) - self.batch_cli = client.BatchV1Api(self.k8s_client) + self.batch_cli = client.BatchV1Api(self.api_client) self.net_cli = client.NetworkingV1Api(self.api_client) self.custom_object_client = client.CustomObjectsApi( - self.k8s_client + self.api_client ) - self.dyn_client = DynamicClient(self.k8s_client) + self.dyn_client = DynamicClient(self.api_client) self.watch_resource = watch.Watch() except OSError: @@ -1912,26 +1935,26 @@ def get_kubernetes_core_objects_count( :param objects: list of the kinds that must be counted :return: a dictionary of Kinds and the number of objects counted """ - api_client = self.api_client - resources = self.get_api_resources_by_group("", "v1") + result = dict[str, int]() - for resource in resources.resources: - if resource.kind in objects: - if api_client: - try: + try: + resources = self.cli.get_api_resources() + for resource in resources.resources: + if resource.kind in objects: + if self.api_client: path_params: Dict[str, str] = {} query_params: List[str] = [] header_params: Dict[str, str] = {} auth_settings = ["BearerToken"] header_params["Accept"] = ( - api_client.select_header_accept( + self.api_client.select_header_accept( ["application/json"] ) ) path = f"/api/{api_version}/{resource.name}" - (data) = api_client.call_api( + (data) = self.api_client.call_api( path, "GET", path_params, @@ -1944,8 +1967,8 @@ def get_kubernetes_core_objects_count( json_obj = ast.literal_eval(data[0]) count = len(json_obj["items"]) result[resource.kind] = count - except ApiException: - pass + except ApiException: + pass return result def get_kubernetes_custom_objects_count( @@ -1958,7 +1981,6 @@ def get_kubernetes_custom_objects_count( :param objects: list of Kinds that must be counted :return: a dictionary of Kinds and number of objects counted """ - custom_object_api = client.CustomObjectsApi(self.api_client) groups = client.ApisApi(self.api_client).get_api_versions().groups result = dict[str, int]() for api in groups: @@ -1978,12 +2000,11 @@ def get_kubernetes_custom_objects_count( ) for resource in data.resources: if resource.kind in objects: - custom_resource = ( - custom_object_api.list_cluster_custom_object( - group=api.name, - version=api.preferred_version.version, - plural=resource.name, - ) + cust_obj = self.custom_object_client + custom_resource = cust_obj.list_cluster_custom_object( + group=api.name, + version=api.preferred_version.version, + plural=resource.name, ) result[resource.kind] = len(custom_resource["items"]) @@ -1992,32 +2013,13 @@ def get_kubernetes_custom_objects_count( return result def get_api_resources_by_group(self, group, version): - api_client = self.api_client - if api_client: - try: - path_params: Dict[str, str] = {} - query_params: List[str] = [] - header_params: Dict[str, str] = {} - auth_settings = ["BearerToken"] - header_params["Accept"] = api_client.select_header_accept( - ["application/json"] - ) - - path = f"/apis/{group}/{version}" - if group == "": - path = f"/api/{version}" - (data) = api_client.call_api( - path, - "GET", - path_params, - query_params, - header_params, - response_type="V1APIResourceList", - auth_settings=auth_settings, - ) - return data[0] - except Exception: - pass + try: + api_response = self.custom_object_client.get_api_resources( + group, version + ) + return api_response + except Exception: + pass return None diff --git a/src/krkn_lib/models/elastic/models.py b/src/krkn_lib/models/elastic/models.py index 86c13ac2..70b2563a 100644 --- a/src/krkn_lib/models/elastic/models.py +++ b/src/krkn_lib/models/elastic/models.py @@ -1,15 +1,16 @@ +import datetime + from elasticsearch_dsl import ( - Keyword, - Text, Date, Document, Float, - Long, - Nested, InnerDoc, Integer, + Keyword, + Long, + Nested, + Text, ) -import datetime from krkn_lib.models.telemetry import ChaosRunTelemetry diff --git a/src/krkn_lib/models/telemetry/models.py b/src/krkn_lib/models/telemetry/models.py index d124312e..105d41ef 100644 --- a/src/krkn_lib/models/telemetry/models.py +++ b/src/krkn_lib/models/telemetry/models.py @@ -1,9 +1,12 @@ from __future__ import annotations + import base64 import json -import yaml from dataclasses import dataclass from datetime import datetime, timezone + +import yaml + from krkn_lib.models.k8s import PodsStatus relevant_event_reasons: frozenset[str] = frozenset( diff --git a/src/krkn_lib/telemetry/ocp/krkn_telemetry_openshift.py b/src/krkn_lib/telemetry/ocp/krkn_telemetry_openshift.py index c5fab51e..1b25b5a7 100644 --- a/src/krkn_lib/telemetry/ocp/krkn_telemetry_openshift.py +++ b/src/krkn_lib/telemetry/ocp/krkn_telemetry_openshift.py @@ -4,6 +4,7 @@ import os import threading from queue import Queue + from krkn_lib.models.telemetry import ChaosRunTelemetry from krkn_lib.ocp import KrknOpenshift from krkn_lib.telemetry.k8s import KrknTelemetryKubernetes diff --git a/src/krkn_lib/tests/base_test.py b/src/krkn_lib/tests/base_test.py index 7b739a00..aa7f3738 100644 --- a/src/krkn_lib/tests/base_test.py +++ b/src/krkn_lib/tests/base_test.py @@ -50,7 +50,7 @@ def setUpClass(cls): cls.lib_telemetry_ocp = KrknTelemetryOpenshift( SafeLogger(), cls.lib_ocp ) - host = cls.lib_k8s.api_client.configuration.host + host = cls.lib_k8s.get_host() logging.disable(logging.CRITICAL) # PROFILER # """init each test""" @@ -110,7 +110,7 @@ def deploy_fedtools( name: str = "fedtools", ): template = self.template_to_pod(name, namespace, random_label) - self.apply_template(template) + self.apply_template(template, namespace) def deploy_fake_kraken( self, @@ -121,17 +121,17 @@ def deploy_fake_kraken( template = self.template_to_pod( "kraken-deployment", namespace, random_label, node_name ) - self.apply_template(template) + self.apply_template(template, namespace) def deploy_job(self, name: str, namespace: str = "default"): template = self.template_to_job(name, namespace) - self.apply_template(template) + self.apply_template(template, namespace) def depoy_alpine(self, name: str, namespace: str = "default"): environment = Environment(loader=FileSystemLoader("src/testdata/")) template = environment.get_template("alpine.j2") content = template.render(name=name, namespace=namespace) - self.apply_template(content) + self.apply_template(content, namespace) def deploy_nginx( self, @@ -168,19 +168,19 @@ def deploy_delayed_readiness_pod( content = template.render( name=name, namespace=namespace, delay=delay, label=label ) - self.apply_template(content) + self.apply_template(content, namespace) def deploy_persistent_volume( self, name: str, storage_class: str, namespace: str ): template = self.template_to_pv(name, storage_class, namespace) - self.apply_template(template) + self.apply_template(template, namespace) def deploy_persistent_volume_claim( self, name: str, storage_class: str, namespace: str ): template = self.template_to_pvc(name, storage_class, namespace) - self.apply_template(template) + self.apply_template(template, namespace) def deploy_deployment(self, name: str, namespace: str = "default"): self.create_deployment(name, namespace) @@ -262,11 +262,11 @@ def file_to_template(self, file: str, name: str, namespace: str): content = template.render(name=name, namespace=namespace) return content - def apply_template(self, template: str): + def apply_template(self, template: str, namespace: str = "default"): with tempfile.NamedTemporaryFile(mode="w") as file: file.write(template) file.flush() - self.lib_k8s.apply_yaml(file.name, "") + self.lib_k8s.apply_yaml(file.name, namespace=namespace) def get_random_string(self, length: int) -> str: letters = string.ascii_lowercase diff --git a/src/krkn_lib/tests/test_krkn_elastic.py b/src/krkn_lib/tests/test_krkn_elastic.py index d9dd93c9..ca76e3ba 100644 --- a/src/krkn_lib/tests/test_krkn_elastic.py +++ b/src/krkn_lib/tests/test_krkn_elastic.py @@ -1,13 +1,9 @@ import datetime import time - import uuid from krkn_lib.elastic.krkn_elastic import KrknElastic -from krkn_lib.models.elastic.models import ( - ElasticAlert, - ElasticMetric, -) +from krkn_lib.models.elastic.models import ElasticAlert, ElasticMetric from krkn_lib.models.telemetry import ChaosRunTelemetry from krkn_lib.tests import BaseTest from krkn_lib.utils import SafeLogger diff --git a/src/krkn_lib/tests/test_krkn_kubernetes.py b/src/krkn_lib/tests/test_krkn_kubernetes.py index 4a151dae..17d98eaa 100644 --- a/src/krkn_lib/tests/test_krkn_kubernetes.py +++ b/src/krkn_lib/tests/test_krkn_kubernetes.py @@ -26,7 +26,7 @@ def test_exec_command(self): self.deploy_namespace(namespace, []) self.deploy_fedtools(namespace=namespace) count = 0 - MAX_RETRIES = 5 + MAX_RETRIES = 10 while not self.lib_k8s.is_pod_running("fedtools", namespace): if count > MAX_RETRIES: self.assertFalse(True, "container failed to become ready") @@ -110,7 +110,7 @@ def test_exec_command_on_node(self): response = self.lib_k8s.exec_command_on_node( "kind-control-plane", ["timedatectl", "status"], - f"test-pod-{time.time()}", + f"test-pod-{self.get_random_string(6)}", ) self.assertTrue( "NTP service: active" or "Network time on: yes" in response @@ -813,6 +813,7 @@ def test_download_folder_from_pod_as_archive(self): for file in archive: self.assertTrue(os.path.isfile(file[1])) self.assertTrue(os.stat(file[1]).st_size > 0) + def test_exists_path_in_pod(self): namespace = "test-" + self.get_random_string(10) diff --git a/src/krkn_lib/tests/test_krkn_telemetry_models.py b/src/krkn_lib/tests/test_krkn_telemetry_models.py index 59a981ff..a21b3501 100644 --- a/src/krkn_lib/tests/test_krkn_telemetry_models.py +++ b/src/krkn_lib/tests/test_krkn_telemetry_models.py @@ -3,8 +3,8 @@ from krkn_lib.models.telemetry import ( ChaosRunTelemetry, - ScenarioTelemetry, ClusterEvent, + ScenarioTelemetry, ) diff --git a/src/krkn_lib/tests/test_utils.py b/src/krkn_lib/tests/test_utils.py index 1eee61bc..c5ffc102 100644 --- a/src/krkn_lib/tests/test_utils.py +++ b/src/krkn_lib/tests/test_utils.py @@ -14,10 +14,10 @@ filter_dictionary, filter_log_line, find_executable_in_path, + get_junit_test_case, get_random_string, get_yaml_item_value, is_host_reachable, - get_junit_test_case, ) diff --git a/src/krkn_lib/tests/test_version.py b/src/krkn_lib/tests/test_version.py index 3c8a2fcf..c85ec7cd 100644 --- a/src/krkn_lib/tests/test_version.py +++ b/src/krkn_lib/tests/test_version.py @@ -1,6 +1,5 @@ -from krkn_lib.version import __version__ - from krkn_lib.tests import BaseTest +from krkn_lib.version import __version__ class VersionTest(BaseTest): diff --git a/src/krkn_lib/utils/functions.py b/src/krkn_lib/utils/functions.py index fd5519fc..0d7c015a 100644 --- a/src/krkn_lib/utils/functions.py +++ b/src/krkn_lib/utils/functions.py @@ -3,9 +3,10 @@ import os import random import re +import socket import string import sys -import socket +import xml.etree.cElementTree as ET from queue import Queue from typing import Optional @@ -13,7 +14,6 @@ from base64io import Base64IO from dateutil import parser from dateutil.parser import ParserError -import xml.etree.cElementTree as ET def decode_base64_file(source_filename: str, destination_filename: str): diff --git a/src/testdata/namespace_template.j2 b/src/testdata/namespace_template.j2 index e0587249..e3bbd9d8 100644 --- a/src/testdata/namespace_template.j2 +++ b/src/testdata/namespace_template.j2 @@ -2,8 +2,13 @@ apiVersion: v1 kind: Namespace metadata: name: {{name}} - {% if labels|length > 1 %} labels: + kubernetes.io/metadata.name: {{name}} + pod-security.kubernetes.io/audit: privileged + pod-security.kubernetes.io/enforce: privileged + pod-security.kubernetes.io/warn: privileged + security.openshift.io/scc.podSecurityLabelSync: "false" + {% if labels|length > 1 %} {% for label in labels %} {{label.name}}: {{label.label}} {% endfor %}