From a0bccd65aa375a0ee5b794cb8715756b542ecfcd Mon Sep 17 00:00:00 2001 From: lugi0 Date: Wed, 23 Oct 2024 15:33:11 +0200 Subject: [PATCH 01/31] Add kserve private endpoint tests Signed-off-by: lugi0 --- .gitignore | 4 + .../model_server/private_endpoint/__init__.py | 0 .../model_server/private_endpoint/conftest.py | 184 ++++++++++++++++++ .../private_endpoint/constants.py | 29 +++ .../model_server/private_endpoint/infra.py | 37 ++++ .../test_kserve_private_endpoint.py | 67 +++++++ .../model_server/private_endpoint/utils.py | 74 +++++++ uv.lock | 30 +-- 8 files changed, 410 insertions(+), 15 deletions(-) create mode 100644 tests/model_serving/model_server/private_endpoint/__init__.py create mode 100644 tests/model_serving/model_server/private_endpoint/conftest.py create mode 100644 tests/model_serving/model_server/private_endpoint/constants.py create mode 100644 tests/model_serving/model_server/private_endpoint/infra.py create mode 100644 tests/model_serving/model_server/private_endpoint/test_kserve_private_endpoint.py create mode 100644 tests/model_serving/model_server/private_endpoint/utils.py diff --git a/.gitignore b/.gitignore index 2dc53ca..e031ebd 100644 --- a/.gitignore +++ b/.gitignore @@ -158,3 +158,7 @@ cython_debug/ # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. .idea/ + +# OS generated files # +.DS_Store +.DS_Store? \ No newline at end of file diff --git a/tests/model_serving/model_server/private_endpoint/__init__.py b/tests/model_serving/model_server/private_endpoint/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/model_serving/model_server/private_endpoint/conftest.py b/tests/model_serving/model_server/private_endpoint/conftest.py new file mode 100644 index 0000000..9dac04d --- /dev/null +++ b/tests/model_serving/model_server/private_endpoint/conftest.py @@ -0,0 +1,184 @@ +import json +import pytest +from ocp_resources.inference_service import InferenceService +from ocp_resources.secret import Secret +from ocp_resources.namespace import Namespace +from ocp_resources.serving_runtime import ServingRuntime +from simple_logger.logger import get_logger +from ocp_resources.service_mesh_member import ServiceMeshMember +from kubernetes.dynamic import DynamicClient + +from tests.model_serving.model_server.private_endpoint.utils import create_sidecar_pod, get_flan_pod, b64_encoded_string +from tests.model_serving.model_server.private_endpoint.infra import create_ns +from tests.model_serving.model_server.storage.conftest import aws_access_key, aws_secret_access_key +from tests.model_serving.model_server.private_endpoint.constants import AWS_REGION, AWS_BUCKET, AWS_ENDPOINT, SR_ANNOTATIONS, SR_CONTAINERS_KSERVE_CAIKIT, SR_SUPPORTED_FORMATS_CAIKIT, SR_VOLUMES + + +LOGGER = get_logger(name=__name__) + + +@pytest.fixture(scope="module") +def endpoint_namespace(admin_client): + yield from create_ns(admin_client=admin_client, name="endpoint-namespace") + + +@pytest.fixture(scope="module") +def diff_namespace(admin_client): + yield from create_ns(admin_client=admin_client, name="diff-namespace") + + +@pytest.fixture() +def endpoint_sr( + admin_client: DynamicClient, + endpoint_namespace: Namespace, +) -> ServingRuntime: + with ServingRuntime( + client=admin_client, + name="flan-example-sr", + namespace=endpoint_namespace.name, + containers=SR_CONTAINERS_KSERVE_CAIKIT, + multi_model=False, + supported_model_formats=SR_SUPPORTED_FORMATS_CAIKIT, + volumes=SR_VOLUMES, + spec_annotations=SR_ANNOTATIONS + ) as model_runtime: + yield model_runtime + + +@pytest.fixture() +def endpoint_s3_secret(admin_client, endpoint_namespace, aws_access_key, aws_secret_access_key): + data = { + "AWS_ACCESS_KEY_ID": b64_encoded_string(aws_access_key), + "AWS_DEFAULT_REGION": b64_encoded_string(AWS_REGION), + "AWS_S3_BUCKET": b64_encoded_string(AWS_BUCKET), + "AWS_S3_ENDPOINT": b64_encoded_string(AWS_REGION), + "AWS_SECRET_ACCESS_KEY": b64_encoded_string(aws_secret_access_key), + } + with Secret( + client=admin_client, + namespace=endpoint_namespace.name, + name="endpoint-s3-secret", + data_dict=data, + wait_for_resource=True, + ) as secret: + yield secret + + +@pytest.fixture() +def endpoint_isvc(admin_client, endpoint_sr, endpoint_s3_secret, storage_config_secret, endpoint_namespace): + predictor = { + "model": { + "modelFormat": { + "name": "caikit", + }, + "name": "kserve-container", + "resources": { + "limits": {"cpu": "2", "memory": "8Gi"}, + "requests": {"cpu": "1", "memory": "4Gi"}, + }, + "runtime": endpoint_sr.name, + "storage": { + "key": "endpoint-s3-secret", + "path": "flan-t5-small/flan-t5-small-caikit", + }, + }, + } + + with InferenceService(client=admin_client, namespace=endpoint_namespace.name, predictor=predictor, name="test") as isvc: + isvc.wait_for_condition(condition="Ready", status="True") + yield isvc + + +@pytest.fixture() +def storage_config_secret(admin_client, endpoint_namespace, endpoint_s3_secret, aws_access_key, aws_secret_access_key): + secret = { + "access_key_id":aws_access_key, + "bucket":AWS_BUCKET, + "default_bucket":AWS_BUCKET, + "endpoint_url":AWS_ENDPOINT, + "region":AWS_REGION, + "secret_access_key":aws_secret_access_key, + "type":"s3" + } + data = { + "endpoint-s3-secret": b64_encoded_string(json.dumps(secret)) + } + with Secret( + client=admin_client, + namespace=endpoint_namespace.name, + data_dict=data, + wait_for_resource=True, + name="storage-config", + ) as storage_config: + yield storage_config + + +@pytest.fixture() +def service_mesh_member(admin_client, diff_namespace): + with ServiceMeshMember( + client=admin_client, + namespace=diff_namespace.name, + name="default", + control_plane_ref={"name": "data-science-smcp", "namespace": "istio-system"}, + wait_for_resource=True, + ) as smm: + yield smm + + +@pytest.fixture() +def endpoint_pod_with_istio_sidecar(admin_client, endpoint_namespace): + pod = create_sidecar_pod( + admin_client=admin_client, + namespace=endpoint_namespace.name, + istio=True, + pod_name="test-with-istio", + ) + yield pod + pod.clean_up() + + +@pytest.fixture() +def endpoint_pod_without_istio_sidecar(admin_client, endpoint_namespace): + pod = create_sidecar_pod( + admin_client=admin_client, + namespace=endpoint_namespace.name, + istio=False, + pod_name="test", + ) + yield pod + pod.clean_up() + + +@pytest.fixture() +def diff_pod_with_istio_sidecar(admin_client, diff_namespace): + pod = create_sidecar_pod( + admin_client=admin_client, + namespace=diff_namespace.name, + istio=True, + pod_name="test-with-istio", + ) + yield pod + pod.clean_up() + + +@pytest.fixture() +def diff_pod_without_istio_sidecar(admin_client, diff_namespace): + pod = create_sidecar_pod( + admin_client=admin_client, + namespace=diff_namespace.name, + istio=False, + pod_name="test", + ) + yield pod + pod.clean_up() + + +@pytest.fixture() +def running_flan_pod(admin_client, endpoint_isvc): + predictor_pod = get_flan_pod( + namespace=endpoint_isvc.namespace, + client=admin_client, + name_prefix=endpoint_isvc.name, + ) + predictor_pod.wait_for_status(status="Running") + predictor_pod.wait_for_condition(condition="Ready", status="True") diff --git a/tests/model_serving/model_server/private_endpoint/constants.py b/tests/model_serving/model_server/private_endpoint/constants.py new file mode 100644 index 0000000..be12f28 --- /dev/null +++ b/tests/model_serving/model_server/private_endpoint/constants.py @@ -0,0 +1,29 @@ +AWS_REGION: str = "us-east-2" +AWS_BUCKET: str = "ods-ci-wisdom" +AWS_ENDPOINT: str = "https://s3.us-east-2.amazonaws.com/" + +SR_CONTAINERS_KSERVE_CAIKIT: list = [ + { + "args": ["--model-name=/mnt/models/artifacts/"], + "command": ["text-generation-launcher"], + "env": [{"name": "HF_HOME", "value": "/tmp/hf_home"}], + "image": "quay.io/modh/text-generation-inference@sha256:294f07b2a94a223a18e559d497a79cac53bf7893f36cfc6c995475b6e431bcfe", + "name": "kserve-container", + "volumeMounts": [{"mountPath": "/dev/shm", "name": "shm"}], + }, + { + "env": [ + {"name": "RUNTIME_LOCAL_MODELS_DIR", "value": "/mnt/models"}, + {"name": "HF_HOME", "value": "/tmp/hf_home"}, + {"name": "RUNTIME_GRPC_ENABLED", "value": "false"}, + {"name": "RUNTIME_HTTP_ENABLED", "value": "true"}, + ], + "image": "quay.io/modh/caikit-tgis-serving@sha256:4e907ce35a3767f5be2f3175a1854e8d4456c43b78cf3df4305bceabcbf0d6e2", + "name": "transformer-container", + "ports": [{"containerPort": 8080, "protocol": "TCP"}], + "volumeMounts": [{"mountPath": "/dev/shm", "name": "shm"}], + }, + ] +SR_SUPPORTED_FORMATS_CAIKIT: list = [{"autoSelect": True, "name": "caikit"},] +SR_VOLUMES: list = [{"emptyDir": {"medium": "Memory", "sizeLimit": "2Gi"}, "name": "shm"}] +SR_ANNOTATIONS: dict = {"prometheus.io/path": "/metrics", "prometheus.io/port": "3000"} \ No newline at end of file diff --git a/tests/model_serving/model_server/private_endpoint/infra.py b/tests/model_serving/model_server/private_endpoint/infra.py new file mode 100644 index 0000000..a4d5087 --- /dev/null +++ b/tests/model_serving/model_server/private_endpoint/infra.py @@ -0,0 +1,37 @@ +from ocp_resources.namespace import Namespace +from ocp_resources.project_project_openshift_io import Project +from ocp_resources.project_request import ProjectRequest + +TIMEOUT_2MIN = 2 * 10 +TIMEOUT_6MIN = 6 * 10 + + +def create_ns( + name, + unprivileged_client=None, + labels=None, + admin_client=None, + teardown=True, + delete_timeout=TIMEOUT_6MIN, +): + if not unprivileged_client: + with Namespace( + client=admin_client, + name=name, + label=labels, + teardown=teardown, + delete_timeout=delete_timeout, + ) as ns: + ns.wait_for_status(status=Namespace.Status.ACTIVE, timeout=TIMEOUT_2MIN) + yield ns + else: + with ProjectRequest(name=name, client=unprivileged_client, teardown=teardown): + project = Project( + name=name, + client=unprivileged_client, + label=labels, + teardown=teardown, + delete_timeout=delete_timeout, + ) + project.wait_for_status(project.Status.ACTIVE, timeout=TIMEOUT_2MIN) + yield project \ No newline at end of file diff --git a/tests/model_serving/model_server/private_endpoint/test_kserve_private_endpoint.py b/tests/model_serving/model_server/private_endpoint/test_kserve_private_endpoint.py new file mode 100644 index 0000000..3392007 --- /dev/null +++ b/tests/model_serving/model_server/private_endpoint/test_kserve_private_endpoint.py @@ -0,0 +1,67 @@ +import pytest +from simple_logger.logger import get_logger +from tests.model_serving.model_server.private_endpoint.utils import curl_from_pod + + +LOGGER = get_logger(name=__name__) + +class TestKserveInternalEndpoint: + def test_deploy_model(self, endpoint_namespace, endpoint_isvc, running_flan_pod): + assert endpoint_isvc.instance.status.modelStatus.states.activeModelState == "Loaded" + assert ( + endpoint_isvc.instance.status.address.url + == f"https://{endpoint_isvc.name}.{endpoint_namespace.name}.svc.cluster.local" + ) + + def test_curl_with_istio( + self, + endpoint_isvc, + endpoint_pod_with_istio_sidecar, + diff_pod_with_istio_sidecar, + service_mesh_member, + ): + LOGGER.info("Testing curl from the same namespace with a pod part of the service mesh") + + curl_stdout = curl_from_pod( + isvc=endpoint_isvc, + pod=endpoint_pod_with_istio_sidecar, + endpoint="health", + ) + assert curl_stdout == "OK" + + LOGGER.info("Testing curl from a different namespace with a pod part of the service mesh") + + curl_stdout = curl_from_pod( + isvc=endpoint_isvc, + pod=diff_pod_with_istio_sidecar, + endpoint="health", + protocol="https", + ) + assert curl_stdout == "OK" + + def test_curl_outside_istio( + self, + endpoint_isvc, + endpoint_pod_without_istio_sidecar, + diff_pod_without_istio_sidecar, + service_mesh_member, + ): + LOGGER.info("Testing curl from the same namespace with a pod not part of the service mesh") + + curl_stdout = curl_from_pod( + isvc=endpoint_isvc, + pod=endpoint_pod_without_istio_sidecar, + endpoint="health", + protocol="https", + ) + assert curl_stdout == "OK" + + LOGGER.info("Testing curl from a different namespace with a pod not part of the service mesh") + + curl_stdout = curl_from_pod( + isvc=endpoint_isvc, + pod=diff_pod_without_istio_sidecar, + endpoint="health", + protocol="https", + ) + assert curl_stdout == "OK" \ No newline at end of file diff --git a/tests/model_serving/model_server/private_endpoint/utils.py b/tests/model_serving/model_server/private_endpoint/utils.py new file mode 100644 index 0000000..59e326c --- /dev/null +++ b/tests/model_serving/model_server/private_endpoint/utils.py @@ -0,0 +1,74 @@ + +import shlex +import base64 + +import pytest +from ocp_resources.pod import Pod +from kubernetes.dynamic.client import DynamicClient +from ocp_resources.inference_service import InferenceService +from pyhelper_utils.shell import run_command +from simple_logger.logger import get_logger + + +LOGGER = get_logger(name=__name__) + + +class FlanPodNotFoundError(Exception): + pass + + +class ProtocolNotSupported(Exception): + def __init__(self, protocol: str): + self.protocol = protocol + self.message = f"Protocol {protocol} is not supported" + super().__init__(self.message) + + +def get_flan_pod(client: DynamicClient, namespace: str, name_prefix: str) -> Pod: + for pod in Pod.get(dyn_client=client, namespace=namespace): + if name_prefix + "-predictor" in pod.name: + return pod + + raise FlanPodNotFoundError(f"No flan predictor pod found in namespace {namespace}") + + +def curl_from_pod( + isvc: InferenceService, + pod: Pod, + endpoint: str, + protocol: str = "http", +) -> str: + if protocol == "http": + tmp = isvc.instance.status.address.url + host = "http://" + tmp.split("://")[1] + + elif protocol == "https": + host = isvc.instance.status.address.url + else: + raise ProtocolNotSupported(protocol) + + return pod.execute(command=shlex.split(f"curl -k {host}/{endpoint}"), ignore_rc=True) + + +def create_sidecar_pod(admin_client, namespace, istio, pod_name): + cmd = f"oc run {pod_name} -n {namespace} --image=registry.access.redhat.com/rhel7/rhel-tools" + if istio: + cmd = f'{cmd} --annotations=sidecar.istio.io/inject="true"' + + cmd += " -- sleep infinity" + + _, _, err = run_command(command=shlex.split(cmd), check=False) + if err: + #pytest.fail(f"Failed on {err}") + LOGGER.info(msg=err) + + pod = Pod(name=pod_name, namespace=namespace, client=admin_client) + pod.wait_for_status(status="Running") + pod.wait_for_condition(condition="Ready", status="True") + return pod + + +def b64_encoded_string(string_to_encode: str) -> str: + # encodes the string to bytes-like, encodes the bytes-like to base 64, decodes the b64 to a string and returns it + # needed for openshift resources expecting b64 encoded values in the yaml + return base64.b64encode(string_to_encode.encode()).decode() \ No newline at end of file diff --git a/uv.lock b/uv.lock index 8a57421..7fd25fd 100644 --- a/uv.lock +++ b/uv.lock @@ -680,7 +680,7 @@ dev = [ [[package]] name = "openshift-python-utilities" -version = "5.0.68" +version = "5.0.70" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "beautifulsoup4" }, @@ -695,11 +695,11 @@ dependencies = [ { name = "semver" }, { name = "timeout-sampler" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e4/73/e829a94696d4d2d3074affe97b2e3591a1776a9dd50a20dde10b93540819/openshift_python_utilities-5.0.68.tar.gz", hash = "sha256:afe16b18eec3b20ca71a41601904bb5d7416bf3ec27877faecc0f0c29b7c2f7c", size = 18225 } +sdist = { url = "https://files.pythonhosted.org/packages/a4/72/fa3d90605f10621b2b3409c400ca7230c36ec4ca1b549f74829c196451e1/openshift_python_utilities-5.0.70.tar.gz", hash = "sha256:dcc8e31f263f04584cda6e327415e72ac00f5a563e7eecbd401b0cc9a6abc382", size = 18300 } [[package]] name = "openshift-python-wrapper" -version = "10.0.93" +version = "10.0.99" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, @@ -719,11 +719,11 @@ dependencies = [ { name = "timeout-sampler" }, { name = "xmltodict" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/5f/d6/6326e4f949f906aac843602a47dfe2b6206fc372f032fadabd3e073e2c1b/openshift_python_wrapper-10.0.93.tar.gz", hash = "sha256:faa0b732a07c81374c211efde62f8b8cb00479f49f3b8d593e9dcbf2c6895977", size = 5775607 } +sdist = { url = "https://files.pythonhosted.org/packages/7c/28/ae14f46ee41e83d977a2bc1b52022407cbbd8bafa70992a47c9eda168c44/openshift_python_wrapper-10.0.99.tar.gz", hash = "sha256:c7c59b035532ab5447a0f6b2b83eb340042c309f74dd6bf7f3fee52b83a4417d", size = 6748161 } [[package]] name = "openshift-python-wrapper-data-collector" -version = "1.0.77" +version = "1.0.80" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "openshift-python-wrapper" }, @@ -731,7 +731,7 @@ dependencies = [ { name = "pytest-testconfig" }, { name = "pyyaml" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/10/2f/6b6a1132910a023a5f544ff97ca2a5dffd2e91985dcdc36f138495c2a120/openshift_python_wrapper_data_collector-1.0.77.tar.gz", hash = "sha256:318e7873b5f8e2fbc57f11f858acc3b162b1909a311c299541256650574cfba2", size = 8311 } +sdist = { url = "https://files.pythonhosted.org/packages/66/12/2c63dd21f6fec507746475a04421ebb5cfd698208a9c96d16b8bd903041d/openshift_python_wrapper_data_collector-1.0.80.tar.gz", hash = "sha256:1398ac6291a67ccaa075711963a1893dc8881164b979aa50d4436342878a0855", size = 8378 } [[package]] name = "orderly-set" @@ -884,7 +884,7 @@ wheels = [ [[package]] name = "pyhelper-utils" -version = "0.0.42" +version = "0.0.43" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "ipdb" }, @@ -893,7 +893,7 @@ dependencies = [ { name = "requests" }, { name = "rich" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/48/d4/f961d328fdc9717a9a6b5679369cccccabb48bf5b8b0da806b6a83425313/pyhelper_utils-0.0.42.tar.gz", hash = "sha256:45d60797b92d463d534e253f9dd5a7e2e2e1c26ea98becc5928cc4546130c20e", size = 9694 } +sdist = { url = "https://files.pythonhosted.org/packages/f0/2e/eaedbd9d73a1fdd7a16bfa6b69cf8e1df147b965f25628f56fd33ed66187/pyhelper_utils-0.0.43.tar.gz", hash = "sha256:a90694f9f9df8bcd5369c53f222dfbcd1946650a5f1255a87184f3c03b4bca30", size = 9748 } [[package]] name = "pynacl" @@ -1003,12 +1003,12 @@ sdist = { url = "https://files.pythonhosted.org/packages/45/60/571982c7af8f5453b [[package]] name = "python-simple-logger" -version = "1.0.40" +version = "1.0.41" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorlog" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/59/f5/83285945b8a6de4c7cd017895ee58fb2b7c0d3b267d18385d52ae2d4a764/python_simple_logger-1.0.40.tar.gz", hash = "sha256:5194447ca8dd743e668f32df880ccd766100339f0d24f922dd4e849066770946", size = 8214 } +sdist = { url = "https://files.pythonhosted.org/packages/4a/2b/761f249251cf81c2327c9e942a7c6642dedc5bf958959df74cad04bb5708/python_simple_logger-1.0.41.tar.gz", hash = "sha256:9890bf0698fc670eaff6430462ac1da16baad51f3139395e9c8056a2df1e7174", size = 8232 } [[package]] name = "python-slugify" @@ -1213,12 +1213,12 @@ wheels = [ [[package]] name = "timeout-sampler" -version = "0.0.46" +version = "0.0.47" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "python-simple-logger" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/4c/ce/8de4b35145fc351236c2bd7f3e7094b3c985674f165a3818164b0ef1198d/timeout_sampler-0.0.46.tar.gz", hash = "sha256:286dadc6920bb8976b1247759ab5f546c56caa1ac8adc878862b1a2a614e7b12", size = 3673 } +sdist = { url = "https://files.pythonhosted.org/packages/44/42/86db619cdcfe9f5fe32ee1e927fdb6954a6b4d7209266b13be9c6b3a947c/timeout_sampler-0.0.47.tar.gz", hash = "sha256:1922eb3417bff24cd3c0dda984fec8f669d0784332b09f179bad2d78b47eca99", size = 3668 } [[package]] name = "tomli" @@ -1276,9 +1276,9 @@ wheels = [ [[package]] name = "xmltodict" -version = "0.14.0" +version = "0.14.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/44/ea/9467a80e5d1722067ad235801883e6eb92f1665c2c629fea7d57fb52775e/xmltodict-0.14.0.tar.gz", hash = "sha256:8b39b25b564fd466be566c9e8a869cc4b5083c2fec7f98665f47bf0853f6cc77", size = 51945 } +sdist = { url = "https://files.pythonhosted.org/packages/50/05/51dcca9a9bf5e1bce52582683ce50980bcadbc4fa5143b9f2b19ab99958f/xmltodict-0.14.2.tar.gz", hash = "sha256:201e7c28bb210e374999d1dde6382923ab0ed1a8a5faeece48ab525b7810a553", size = 51942 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c6/99/23393ec588b33a63b2471df7ab8e583eca117c63fb47b95545e5e747be75/xmltodict-0.14.0-py2.py3-none-any.whl", hash = "sha256:6dd20b8de8d0eb84d175ec706cc17b53df236615b0980de33537736319e5ee85", size = 9993 }, + { url = "https://files.pythonhosted.org/packages/d6/45/fc303eb433e8a2a271739c98e953728422fa61a3c1f36077a49e395c972e/xmltodict-0.14.2-py2.py3-none-any.whl", hash = "sha256:20cc7d723ed729276e808f26fb6b3599f786cbc37e06c65e192ba77c40f20aac", size = 9981 }, ] From 078605a4eb9f327e2b48dc2b1d291a712aea04d9 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 23 Oct 2024 13:38:49 +0000 Subject: [PATCH 02/31] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .gitignore | 2 +- .../model_server/private_endpoint/conftest.py | 37 ++++++++------ .../private_endpoint/constants.py | 48 ++++++++++--------- .../model_server/private_endpoint/infra.py | 2 +- .../test_kserve_private_endpoint.py | 8 ++-- .../model_server/private_endpoint/utils.py | 6 +-- 6 files changed, 55 insertions(+), 48 deletions(-) diff --git a/.gitignore b/.gitignore index e031ebd..c9d5b3b 100644 --- a/.gitignore +++ b/.gitignore @@ -161,4 +161,4 @@ cython_debug/ # OS generated files # .DS_Store -.DS_Store? \ No newline at end of file +.DS_Store? diff --git a/tests/model_serving/model_server/private_endpoint/conftest.py b/tests/model_serving/model_server/private_endpoint/conftest.py index 9dac04d..b0b7c86 100644 --- a/tests/model_serving/model_server/private_endpoint/conftest.py +++ b/tests/model_serving/model_server/private_endpoint/conftest.py @@ -10,8 +10,15 @@ from tests.model_serving.model_server.private_endpoint.utils import create_sidecar_pod, get_flan_pod, b64_encoded_string from tests.model_serving.model_server.private_endpoint.infra import create_ns -from tests.model_serving.model_server.storage.conftest import aws_access_key, aws_secret_access_key -from tests.model_serving.model_server.private_endpoint.constants import AWS_REGION, AWS_BUCKET, AWS_ENDPOINT, SR_ANNOTATIONS, SR_CONTAINERS_KSERVE_CAIKIT, SR_SUPPORTED_FORMATS_CAIKIT, SR_VOLUMES +from tests.model_serving.model_server.private_endpoint.constants import ( + AWS_REGION, + AWS_BUCKET, + AWS_ENDPOINT, + SR_ANNOTATIONS, + SR_CONTAINERS_KSERVE_CAIKIT, + SR_SUPPORTED_FORMATS_CAIKIT, + SR_VOLUMES, +) LOGGER = get_logger(name=__name__) @@ -40,7 +47,7 @@ def endpoint_sr( multi_model=False, supported_model_formats=SR_SUPPORTED_FORMATS_CAIKIT, volumes=SR_VOLUMES, - spec_annotations=SR_ANNOTATIONS + spec_annotations=SR_ANNOTATIONS, ) as model_runtime: yield model_runtime @@ -70,7 +77,7 @@ def endpoint_isvc(admin_client, endpoint_sr, endpoint_s3_secret, storage_config_ "model": { "modelFormat": { "name": "caikit", - }, + }, "name": "kserve-container", "resources": { "limits": {"cpu": "2", "memory": "8Gi"}, @@ -84,7 +91,9 @@ def endpoint_isvc(admin_client, endpoint_sr, endpoint_s3_secret, storage_config_ }, } - with InferenceService(client=admin_client, namespace=endpoint_namespace.name, predictor=predictor, name="test") as isvc: + with InferenceService( + client=admin_client, namespace=endpoint_namespace.name, predictor=predictor, name="test" + ) as isvc: isvc.wait_for_condition(condition="Ready", status="True") yield isvc @@ -92,17 +101,15 @@ def endpoint_isvc(admin_client, endpoint_sr, endpoint_s3_secret, storage_config_ @pytest.fixture() def storage_config_secret(admin_client, endpoint_namespace, endpoint_s3_secret, aws_access_key, aws_secret_access_key): secret = { - "access_key_id":aws_access_key, - "bucket":AWS_BUCKET, - "default_bucket":AWS_BUCKET, - "endpoint_url":AWS_ENDPOINT, - "region":AWS_REGION, - "secret_access_key":aws_secret_access_key, - "type":"s3" - } - data = { - "endpoint-s3-secret": b64_encoded_string(json.dumps(secret)) + "access_key_id": aws_access_key, + "bucket": AWS_BUCKET, + "default_bucket": AWS_BUCKET, + "endpoint_url": AWS_ENDPOINT, + "region": AWS_REGION, + "secret_access_key": aws_secret_access_key, + "type": "s3", } + data = {"endpoint-s3-secret": b64_encoded_string(json.dumps(secret))} with Secret( client=admin_client, namespace=endpoint_namespace.name, diff --git a/tests/model_serving/model_server/private_endpoint/constants.py b/tests/model_serving/model_server/private_endpoint/constants.py index be12f28..52aec26 100644 --- a/tests/model_serving/model_server/private_endpoint/constants.py +++ b/tests/model_serving/model_server/private_endpoint/constants.py @@ -3,27 +3,29 @@ AWS_ENDPOINT: str = "https://s3.us-east-2.amazonaws.com/" SR_CONTAINERS_KSERVE_CAIKIT: list = [ - { - "args": ["--model-name=/mnt/models/artifacts/"], - "command": ["text-generation-launcher"], - "env": [{"name": "HF_HOME", "value": "/tmp/hf_home"}], - "image": "quay.io/modh/text-generation-inference@sha256:294f07b2a94a223a18e559d497a79cac53bf7893f36cfc6c995475b6e431bcfe", - "name": "kserve-container", - "volumeMounts": [{"mountPath": "/dev/shm", "name": "shm"}], - }, - { - "env": [ - {"name": "RUNTIME_LOCAL_MODELS_DIR", "value": "/mnt/models"}, - {"name": "HF_HOME", "value": "/tmp/hf_home"}, - {"name": "RUNTIME_GRPC_ENABLED", "value": "false"}, - {"name": "RUNTIME_HTTP_ENABLED", "value": "true"}, - ], - "image": "quay.io/modh/caikit-tgis-serving@sha256:4e907ce35a3767f5be2f3175a1854e8d4456c43b78cf3df4305bceabcbf0d6e2", - "name": "transformer-container", - "ports": [{"containerPort": 8080, "protocol": "TCP"}], - "volumeMounts": [{"mountPath": "/dev/shm", "name": "shm"}], - }, - ] -SR_SUPPORTED_FORMATS_CAIKIT: list = [{"autoSelect": True, "name": "caikit"},] + { + "args": ["--model-name=/mnt/models/artifacts/"], + "command": ["text-generation-launcher"], + "env": [{"name": "HF_HOME", "value": "/tmp/hf_home"}], + "image": "quay.io/modh/text-generation-inference@sha256:294f07b2a94a223a18e559d497a79cac53bf7893f36cfc6c995475b6e431bcfe", + "name": "kserve-container", + "volumeMounts": [{"mountPath": "/dev/shm", "name": "shm"}], + }, + { + "env": [ + {"name": "RUNTIME_LOCAL_MODELS_DIR", "value": "/mnt/models"}, + {"name": "HF_HOME", "value": "/tmp/hf_home"}, + {"name": "RUNTIME_GRPC_ENABLED", "value": "false"}, + {"name": "RUNTIME_HTTP_ENABLED", "value": "true"}, + ], + "image": "quay.io/modh/caikit-tgis-serving@sha256:4e907ce35a3767f5be2f3175a1854e8d4456c43b78cf3df4305bceabcbf0d6e2", + "name": "transformer-container", + "ports": [{"containerPort": 8080, "protocol": "TCP"}], + "volumeMounts": [{"mountPath": "/dev/shm", "name": "shm"}], + }, +] +SR_SUPPORTED_FORMATS_CAIKIT: list = [ + {"autoSelect": True, "name": "caikit"}, +] SR_VOLUMES: list = [{"emptyDir": {"medium": "Memory", "sizeLimit": "2Gi"}, "name": "shm"}] -SR_ANNOTATIONS: dict = {"prometheus.io/path": "/metrics", "prometheus.io/port": "3000"} \ No newline at end of file +SR_ANNOTATIONS: dict = {"prometheus.io/path": "/metrics", "prometheus.io/port": "3000"} diff --git a/tests/model_serving/model_server/private_endpoint/infra.py b/tests/model_serving/model_server/private_endpoint/infra.py index a4d5087..422141d 100644 --- a/tests/model_serving/model_server/private_endpoint/infra.py +++ b/tests/model_serving/model_server/private_endpoint/infra.py @@ -34,4 +34,4 @@ def create_ns( delete_timeout=delete_timeout, ) project.wait_for_status(project.Status.ACTIVE, timeout=TIMEOUT_2MIN) - yield project \ No newline at end of file + yield project diff --git a/tests/model_serving/model_server/private_endpoint/test_kserve_private_endpoint.py b/tests/model_serving/model_server/private_endpoint/test_kserve_private_endpoint.py index 3392007..6f0e941 100644 --- a/tests/model_serving/model_server/private_endpoint/test_kserve_private_endpoint.py +++ b/tests/model_serving/model_server/private_endpoint/test_kserve_private_endpoint.py @@ -1,10 +1,10 @@ -import pytest from simple_logger.logger import get_logger from tests.model_serving.model_server.private_endpoint.utils import curl_from_pod LOGGER = get_logger(name=__name__) + class TestKserveInternalEndpoint: def test_deploy_model(self, endpoint_namespace, endpoint_isvc, running_flan_pod): assert endpoint_isvc.instance.status.modelStatus.states.activeModelState == "Loaded" @@ -32,8 +32,8 @@ def test_curl_with_istio( LOGGER.info("Testing curl from a different namespace with a pod part of the service mesh") curl_stdout = curl_from_pod( - isvc=endpoint_isvc, - pod=diff_pod_with_istio_sidecar, + isvc=endpoint_isvc, + pod=diff_pod_with_istio_sidecar, endpoint="health", protocol="https", ) @@ -64,4 +64,4 @@ def test_curl_outside_istio( endpoint="health", protocol="https", ) - assert curl_stdout == "OK" \ No newline at end of file + assert curl_stdout == "OK" diff --git a/tests/model_serving/model_server/private_endpoint/utils.py b/tests/model_serving/model_server/private_endpoint/utils.py index 59e326c..6ebb535 100644 --- a/tests/model_serving/model_server/private_endpoint/utils.py +++ b/tests/model_serving/model_server/private_endpoint/utils.py @@ -1,8 +1,6 @@ - import shlex import base64 -import pytest from ocp_resources.pod import Pod from kubernetes.dynamic.client import DynamicClient from ocp_resources.inference_service import InferenceService @@ -59,7 +57,7 @@ def create_sidecar_pod(admin_client, namespace, istio, pod_name): _, _, err = run_command(command=shlex.split(cmd), check=False) if err: - #pytest.fail(f"Failed on {err}") + # pytest.fail(f"Failed on {err}") LOGGER.info(msg=err) pod = Pod(name=pod_name, namespace=namespace, client=admin_client) @@ -71,4 +69,4 @@ def create_sidecar_pod(admin_client, namespace, istio, pod_name): def b64_encoded_string(string_to_encode: str) -> str: # encodes the string to bytes-like, encodes the bytes-like to base 64, decodes the b64 to a string and returns it # needed for openshift resources expecting b64 encoded values in the yaml - return base64.b64encode(string_to_encode.encode()).decode() \ No newline at end of file + return base64.b64encode(string_to_encode.encode()).decode() From b44312f7ca52ecc6f2962fe65078d52e70476c44 Mon Sep 17 00:00:00 2001 From: lugi0 Date: Wed, 23 Oct 2024 15:51:58 +0200 Subject: [PATCH 03/31] Fix typing annotations Signed-off-by: lugi0 --- .../model_server/private_endpoint/constants.py | 10 ++++++---- .../model_server/private_endpoint/infra.py | 17 ++++++++++------- .../model_server/private_endpoint/utils.py | 7 ++++++- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/tests/model_serving/model_server/private_endpoint/constants.py b/tests/model_serving/model_server/private_endpoint/constants.py index 52aec26..f47df4e 100644 --- a/tests/model_serving/model_server/private_endpoint/constants.py +++ b/tests/model_serving/model_server/private_endpoint/constants.py @@ -1,8 +1,10 @@ +from typing import Dict, List + AWS_REGION: str = "us-east-2" AWS_BUCKET: str = "ods-ci-wisdom" AWS_ENDPOINT: str = "https://s3.us-east-2.amazonaws.com/" -SR_CONTAINERS_KSERVE_CAIKIT: list = [ +SR_CONTAINERS_KSERVE_CAIKIT: List[Dict[str,str]] = [ { "args": ["--model-name=/mnt/models/artifacts/"], "command": ["text-generation-launcher"], @@ -24,8 +26,8 @@ "volumeMounts": [{"mountPath": "/dev/shm", "name": "shm"}], }, ] -SR_SUPPORTED_FORMATS_CAIKIT: list = [ +SR_SUPPORTED_FORMATS_CAIKIT: List[Dict[str,str]] = [ {"autoSelect": True, "name": "caikit"}, ] -SR_VOLUMES: list = [{"emptyDir": {"medium": "Memory", "sizeLimit": "2Gi"}, "name": "shm"}] -SR_ANNOTATIONS: dict = {"prometheus.io/path": "/metrics", "prometheus.io/port": "3000"} +SR_VOLUMES: List[Dict[str,str]] = [{"emptyDir": {"medium": "Memory", "sizeLimit": "2Gi"}, "name": "shm"}] +SR_ANNOTATIONS: Dict[str,str] = {"prometheus.io/path": "/metrics", "prometheus.io/port": "3000"} diff --git a/tests/model_serving/model_server/private_endpoint/infra.py b/tests/model_serving/model_server/private_endpoint/infra.py index 422141d..129a5df 100644 --- a/tests/model_serving/model_server/private_endpoint/infra.py +++ b/tests/model_serving/model_server/private_endpoint/infra.py @@ -1,3 +1,6 @@ +from typing import Generator, Dict + +from kubernetes.dynamic import DynamicClient from ocp_resources.namespace import Namespace from ocp_resources.project_project_openshift_io import Project from ocp_resources.project_request import ProjectRequest @@ -7,13 +10,13 @@ def create_ns( - name, - unprivileged_client=None, - labels=None, - admin_client=None, - teardown=True, - delete_timeout=TIMEOUT_6MIN, -): + name: str, + unprivileged_client: DynamicClient = None, + labels: Dict[str, str] =None, + admin_client: DynamicClient = None, + teardown: bool = True, + delete_timeout: int = TIMEOUT_6MIN, +) -> Generator[Namespace] | Generator[Project] : if not unprivileged_client: with Namespace( client=admin_client, diff --git a/tests/model_serving/model_server/private_endpoint/utils.py b/tests/model_serving/model_server/private_endpoint/utils.py index 6ebb535..c7e1c79 100644 --- a/tests/model_serving/model_server/private_endpoint/utils.py +++ b/tests/model_serving/model_server/private_endpoint/utils.py @@ -48,7 +48,12 @@ def curl_from_pod( return pod.execute(command=shlex.split(f"curl -k {host}/{endpoint}"), ignore_rc=True) -def create_sidecar_pod(admin_client, namespace, istio, pod_name): +def create_sidecar_pod( + admin_client: DynamicClient, + namespace: str, + istio: bool, + pod_name: str, +) -> Pod: cmd = f"oc run {pod_name} -n {namespace} --image=registry.access.redhat.com/rhel7/rhel-tools" if istio: cmd = f'{cmd} --annotations=sidecar.istio.io/inject="true"' From 9fbaf1f32a0607c9bbbe375d1c1669841317b6bf Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 23 Oct 2024 13:52:14 +0000 Subject: [PATCH 04/31] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .../model_server/private_endpoint/constants.py | 8 ++++---- .../model_serving/model_server/private_endpoint/infra.py | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/model_serving/model_server/private_endpoint/constants.py b/tests/model_serving/model_server/private_endpoint/constants.py index f47df4e..c7ff4dd 100644 --- a/tests/model_serving/model_server/private_endpoint/constants.py +++ b/tests/model_serving/model_server/private_endpoint/constants.py @@ -4,7 +4,7 @@ AWS_BUCKET: str = "ods-ci-wisdom" AWS_ENDPOINT: str = "https://s3.us-east-2.amazonaws.com/" -SR_CONTAINERS_KSERVE_CAIKIT: List[Dict[str,str]] = [ +SR_CONTAINERS_KSERVE_CAIKIT: List[Dict[str, str]] = [ { "args": ["--model-name=/mnt/models/artifacts/"], "command": ["text-generation-launcher"], @@ -26,8 +26,8 @@ "volumeMounts": [{"mountPath": "/dev/shm", "name": "shm"}], }, ] -SR_SUPPORTED_FORMATS_CAIKIT: List[Dict[str,str]] = [ +SR_SUPPORTED_FORMATS_CAIKIT: List[Dict[str, str]] = [ {"autoSelect": True, "name": "caikit"}, ] -SR_VOLUMES: List[Dict[str,str]] = [{"emptyDir": {"medium": "Memory", "sizeLimit": "2Gi"}, "name": "shm"}] -SR_ANNOTATIONS: Dict[str,str] = {"prometheus.io/path": "/metrics", "prometheus.io/port": "3000"} +SR_VOLUMES: List[Dict[str, str]] = [{"emptyDir": {"medium": "Memory", "sizeLimit": "2Gi"}, "name": "shm"}] +SR_ANNOTATIONS: Dict[str, str] = {"prometheus.io/path": "/metrics", "prometheus.io/port": "3000"} diff --git a/tests/model_serving/model_server/private_endpoint/infra.py b/tests/model_serving/model_server/private_endpoint/infra.py index 129a5df..4d15754 100644 --- a/tests/model_serving/model_server/private_endpoint/infra.py +++ b/tests/model_serving/model_server/private_endpoint/infra.py @@ -12,11 +12,11 @@ def create_ns( name: str, unprivileged_client: DynamicClient = None, - labels: Dict[str, str] =None, + labels: Dict[str, str] = None, admin_client: DynamicClient = None, teardown: bool = True, delete_timeout: int = TIMEOUT_6MIN, -) -> Generator[Namespace] | Generator[Project] : +) -> Generator[Namespace] | Generator[Project]: if not unprivileged_client: with Namespace( client=admin_client, From df6c2e023d058f0558458b75b6640b9abf708e28 Mon Sep 17 00:00:00 2001 From: lugi0 Date: Wed, 23 Oct 2024 16:27:54 +0200 Subject: [PATCH 05/31] Fix pre-commit checks, add mypy ini file for vscode extension integration, specify in README that pre-commit shoulb be run and needs NPM installed Signed-off-by: lugi0 --- README.md | 2 + mypy.ini | 8 ++++ .../model_server/private_endpoint/conftest.py | 40 +++++++++++++------ .../private_endpoint/constants.py | 8 ++-- .../model_server/private_endpoint/infra.py | 5 ++- .../test_kserve_private_endpoint.py | 34 ++++++++++------ 6 files changed, 66 insertions(+), 31 deletions(-) create mode 100644 mypy.ini diff --git a/README.md b/README.md index 706414c..41bec21 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,4 @@ # opendatahub-tests # TODO: update file + +# Run `pre-commit` before committing. You will need npm installed to do so. diff --git a/mypy.ini b/mypy.ini new file mode 100644 index 0000000..815166a --- /dev/null +++ b/mypy.ini @@ -0,0 +1,8 @@ +[mypy] +check_untyped_defs = true +disallow_any_generics = true +disallow_incomplete_defs = true +disallow_untyped_defs = true +no_implicit_optional = true +show_error_codes = true +warn_unused_ignores = true diff --git a/tests/model_serving/model_server/private_endpoint/conftest.py b/tests/model_serving/model_server/private_endpoint/conftest.py index b0b7c86..b31fa51 100644 --- a/tests/model_serving/model_server/private_endpoint/conftest.py +++ b/tests/model_serving/model_server/private_endpoint/conftest.py @@ -1,9 +1,11 @@ import json import pytest +from typing import Generator from ocp_resources.inference_service import InferenceService from ocp_resources.secret import Secret from ocp_resources.namespace import Namespace from ocp_resources.serving_runtime import ServingRuntime +from ocp_resources.pod import Pod from simple_logger.logger import get_logger from ocp_resources.service_mesh_member import ServiceMeshMember from kubernetes.dynamic import DynamicClient @@ -25,12 +27,12 @@ @pytest.fixture(scope="module") -def endpoint_namespace(admin_client): +def endpoint_namespace(admin_client: DynamicClient) -> Generator[Namespace]: yield from create_ns(admin_client=admin_client, name="endpoint-namespace") @pytest.fixture(scope="module") -def diff_namespace(admin_client): +def diff_namespace(admin_client: DynamicClient) -> Generator[Namespace]: yield from create_ns(admin_client=admin_client, name="diff-namespace") @@ -38,7 +40,7 @@ def diff_namespace(admin_client): def endpoint_sr( admin_client: DynamicClient, endpoint_namespace: Namespace, -) -> ServingRuntime: +) -> Generator[ServingRuntime]: with ServingRuntime( client=admin_client, name="flan-example-sr", @@ -53,7 +55,9 @@ def endpoint_sr( @pytest.fixture() -def endpoint_s3_secret(admin_client, endpoint_namespace, aws_access_key, aws_secret_access_key): +def endpoint_s3_secret( + admin_client: DynamicClient, endpoint_namespace: Namespace, aws_access_key: str, aws_secret_access_key: str +) -> Generator[Secret]: data = { "AWS_ACCESS_KEY_ID": b64_encoded_string(aws_access_key), "AWS_DEFAULT_REGION": b64_encoded_string(AWS_REGION), @@ -72,7 +76,13 @@ def endpoint_s3_secret(admin_client, endpoint_namespace, aws_access_key, aws_sec @pytest.fixture() -def endpoint_isvc(admin_client, endpoint_sr, endpoint_s3_secret, storage_config_secret, endpoint_namespace): +def endpoint_isvc( + admin_client: DynamicClient, + endpoint_sr: ServingRuntime, + endpoint_s3_secret: Secret, + storage_config_secret: Secret, + endpoint_namespace: Namespace, +) -> Generator[InferenceService]: predictor = { "model": { "modelFormat": { @@ -99,7 +109,13 @@ def endpoint_isvc(admin_client, endpoint_sr, endpoint_s3_secret, storage_config_ @pytest.fixture() -def storage_config_secret(admin_client, endpoint_namespace, endpoint_s3_secret, aws_access_key, aws_secret_access_key): +def storage_config_secret( + admin_client: DynamicClient, + endpoint_namespace: Namespace, + endpoint_s3_secret: Secret, + aws_access_key: str, + aws_secret_access_key: str, +) -> Generator[Secret]: secret = { "access_key_id": aws_access_key, "bucket": AWS_BUCKET, @@ -121,7 +137,7 @@ def storage_config_secret(admin_client, endpoint_namespace, endpoint_s3_secret, @pytest.fixture() -def service_mesh_member(admin_client, diff_namespace): +def service_mesh_member(admin_client: DynamicClient, diff_namespace: Namespace) -> Generator[ServiceMeshMember]: with ServiceMeshMember( client=admin_client, namespace=diff_namespace.name, @@ -133,7 +149,7 @@ def service_mesh_member(admin_client, diff_namespace): @pytest.fixture() -def endpoint_pod_with_istio_sidecar(admin_client, endpoint_namespace): +def endpoint_pod_with_istio_sidecar(admin_client: DynamicClient, endpoint_namespace: Namespace) -> Generator[Pod]: pod = create_sidecar_pod( admin_client=admin_client, namespace=endpoint_namespace.name, @@ -145,7 +161,7 @@ def endpoint_pod_with_istio_sidecar(admin_client, endpoint_namespace): @pytest.fixture() -def endpoint_pod_without_istio_sidecar(admin_client, endpoint_namespace): +def endpoint_pod_without_istio_sidecar(admin_client: DynamicClient, endpoint_namespace: Namespace) -> Generator[Pod]: pod = create_sidecar_pod( admin_client=admin_client, namespace=endpoint_namespace.name, @@ -157,7 +173,7 @@ def endpoint_pod_without_istio_sidecar(admin_client, endpoint_namespace): @pytest.fixture() -def diff_pod_with_istio_sidecar(admin_client, diff_namespace): +def diff_pod_with_istio_sidecar(admin_client: DynamicClient, diff_namespace: Namespace) -> Generator[Pod]: pod = create_sidecar_pod( admin_client=admin_client, namespace=diff_namespace.name, @@ -169,7 +185,7 @@ def diff_pod_with_istio_sidecar(admin_client, diff_namespace): @pytest.fixture() -def diff_pod_without_istio_sidecar(admin_client, diff_namespace): +def diff_pod_without_istio_sidecar(admin_client: DynamicClient, diff_namespace: Namespace) -> Generator[Pod]: pod = create_sidecar_pod( admin_client=admin_client, namespace=diff_namespace.name, @@ -181,7 +197,7 @@ def diff_pod_without_istio_sidecar(admin_client, diff_namespace): @pytest.fixture() -def running_flan_pod(admin_client, endpoint_isvc): +def running_flan_pod(admin_client: DynamicClient, endpoint_isvc: InferenceService) -> None: predictor_pod = get_flan_pod( namespace=endpoint_isvc.namespace, client=admin_client, diff --git a/tests/model_serving/model_server/private_endpoint/constants.py b/tests/model_serving/model_server/private_endpoint/constants.py index c7ff4dd..166bcd6 100644 --- a/tests/model_serving/model_server/private_endpoint/constants.py +++ b/tests/model_serving/model_server/private_endpoint/constants.py @@ -1,10 +1,10 @@ -from typing import Dict, List +from typing import Dict, List, Any AWS_REGION: str = "us-east-2" AWS_BUCKET: str = "ods-ci-wisdom" AWS_ENDPOINT: str = "https://s3.us-east-2.amazonaws.com/" -SR_CONTAINERS_KSERVE_CAIKIT: List[Dict[str, str]] = [ +SR_CONTAINERS_KSERVE_CAIKIT: List[Dict[Any, Any]] = [ { "args": ["--model-name=/mnt/models/artifacts/"], "command": ["text-generation-launcher"], @@ -26,8 +26,8 @@ "volumeMounts": [{"mountPath": "/dev/shm", "name": "shm"}], }, ] -SR_SUPPORTED_FORMATS_CAIKIT: List[Dict[str, str]] = [ +SR_SUPPORTED_FORMATS_CAIKIT: List[Dict[Any, Any]] = [ {"autoSelect": True, "name": "caikit"}, ] -SR_VOLUMES: List[Dict[str, str]] = [{"emptyDir": {"medium": "Memory", "sizeLimit": "2Gi"}, "name": "shm"}] +SR_VOLUMES: List[Dict[Any, Any]] = [{"emptyDir": {"medium": "Memory", "sizeLimit": "2Gi"}, "name": "shm"}] SR_ANNOTATIONS: Dict[str, str] = {"prometheus.io/path": "/metrics", "prometheus.io/port": "3000"} diff --git a/tests/model_serving/model_server/private_endpoint/infra.py b/tests/model_serving/model_server/private_endpoint/infra.py index 4d15754..04a6062 100644 --- a/tests/model_serving/model_server/private_endpoint/infra.py +++ b/tests/model_serving/model_server/private_endpoint/infra.py @@ -1,4 +1,4 @@ -from typing import Generator, Dict +from typing import Generator, Dict, Optional from kubernetes.dynamic import DynamicClient from ocp_resources.namespace import Namespace @@ -12,10 +12,11 @@ def create_ns( name: str, unprivileged_client: DynamicClient = None, - labels: Dict[str, str] = None, + labels: Optional[Dict[str, str]] = None, admin_client: DynamicClient = None, teardown: bool = True, delete_timeout: int = TIMEOUT_6MIN, +) -> Generator[Namespace] | Generator[Project]: ) -> Generator[Namespace] | Generator[Project]: if not unprivileged_client: with Namespace( diff --git a/tests/model_serving/model_server/private_endpoint/test_kserve_private_endpoint.py b/tests/model_serving/model_server/private_endpoint/test_kserve_private_endpoint.py index 6f0e941..0b1ed42 100644 --- a/tests/model_serving/model_server/private_endpoint/test_kserve_private_endpoint.py +++ b/tests/model_serving/model_server/private_endpoint/test_kserve_private_endpoint.py @@ -1,4 +1,10 @@ +from typing import Self + from simple_logger.logger import get_logger +from ocp_resources.namespace import Namespace +from ocp_resources.inference_service import InferenceService +from ocp_resources.pod import Pod +from ocp_resources.service_mesh_member import ServiceMeshMember from tests.model_serving.model_server.private_endpoint.utils import curl_from_pod @@ -6,7 +12,9 @@ class TestKserveInternalEndpoint: - def test_deploy_model(self, endpoint_namespace, endpoint_isvc, running_flan_pod): + def test_deploy_model( + self: Self, endpoint_namespace: Namespace, endpoint_isvc: InferenceService, running_flan_pod: Pod + ) -> None: assert endpoint_isvc.instance.status.modelStatus.states.activeModelState == "Loaded" assert ( endpoint_isvc.instance.status.address.url @@ -14,12 +22,12 @@ def test_deploy_model(self, endpoint_namespace, endpoint_isvc, running_flan_pod) ) def test_curl_with_istio( - self, - endpoint_isvc, - endpoint_pod_with_istio_sidecar, - diff_pod_with_istio_sidecar, - service_mesh_member, - ): + self: Self, + endpoint_isvc: InferenceService, + endpoint_pod_with_istio_sidecar: Pod, + diff_pod_with_istio_sidecar: Pod, + service_mesh_member: ServiceMeshMember, + ) -> None: LOGGER.info("Testing curl from the same namespace with a pod part of the service mesh") curl_stdout = curl_from_pod( @@ -40,12 +48,12 @@ def test_curl_with_istio( assert curl_stdout == "OK" def test_curl_outside_istio( - self, - endpoint_isvc, - endpoint_pod_without_istio_sidecar, - diff_pod_without_istio_sidecar, - service_mesh_member, - ): + self: Self, + endpoint_isvc: InferenceService, + endpoint_pod_without_istio_sidecar: Pod, + diff_pod_without_istio_sidecar: Pod, + service_mesh_member: ServiceMeshMember, + ) -> None: LOGGER.info("Testing curl from the same namespace with a pod not part of the service mesh") curl_stdout = curl_from_pod( From 863127ccdcb24da30d6a1e2b288e27218a715678 Mon Sep 17 00:00:00 2001 From: lugi0 Date: Wed, 23 Oct 2024 16:37:35 +0200 Subject: [PATCH 06/31] Fix typo in function signature Signed-off-by: lugi0 --- tests/model_serving/model_server/private_endpoint/infra.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/model_serving/model_server/private_endpoint/infra.py b/tests/model_serving/model_server/private_endpoint/infra.py index 04a6062..303aea0 100644 --- a/tests/model_serving/model_server/private_endpoint/infra.py +++ b/tests/model_serving/model_server/private_endpoint/infra.py @@ -16,7 +16,6 @@ def create_ns( admin_client: DynamicClient = None, teardown: bool = True, delete_timeout: int = TIMEOUT_6MIN, -) -> Generator[Namespace] | Generator[Project]: ) -> Generator[Namespace] | Generator[Project]: if not unprivileged_client: with Namespace( From 39dc8baae71372f076eb16d17bf25b375af2597d Mon Sep 17 00:00:00 2001 From: Ruth Netser Date: Sun, 27 Oct 2024 10:09:31 +0200 Subject: [PATCH 07/31] Update renovate.json (#26) --- renovate.json | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/renovate.json b/renovate.json index 771889a..e748778 100644 --- a/renovate.json +++ b/renovate.json @@ -1 +1,19 @@ -{"$schema": "https://docs.renovatebot.com/renovate-schema.json", "packageRules": [{"matchPackagePatterns": ["python-simple-logger", "pytest-testconfig", "pytest-progress", "pyyaml", "openshift-python-utilities", "openshift-python-wrapper", "ipdb", "ipython"], "groupName": "python-deps"}]} +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + ":dependencyDashboard", + ":maintainLockFilesWeekly", + ":prHourlyLimitNone" + ], + "prConcurrentLimit": 0, + "lockFileMaintenance": { + "enabled": true + }, + "baseBranches": ["main"], + "packageRules": [ + { + "matchPackagePatterns": ["*"], + "groupName": "python-dependencies" + } + ] +} From 87104c56b7bc5a7ff8785e78ddf182ec0dc9d787 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 28 Oct 2024 21:05:12 +0200 Subject: [PATCH 08/31] Lock file maintenance (#28) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- uv.lock | 117 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 58 insertions(+), 59 deletions(-) diff --git a/uv.lock b/uv.lock index 7fd25fd..baf86d5 100644 --- a/uv.lock +++ b/uv.lock @@ -323,39 +323,39 @@ wheels = [ [[package]] name = "cryptography" -version = "43.0.1" +version = "43.0.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/de/ba/0664727028b37e249e73879348cc46d45c5c1a2a2e81e8166462953c5755/cryptography-43.0.1.tar.gz", hash = "sha256:203e92a75716d8cfb491dc47c79e17d0d9207ccffcbcb35f598fbe463ae3444d", size = 686927 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/58/28/b92c98a04ba762f8cdeb54eba5c4c84e63cac037a7c5e70117d337b15ad6/cryptography-43.0.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d", size = 6223222 }, - { url = "https://files.pythonhosted.org/packages/33/13/1193774705783ba364121aa2a60132fa31a668b8ababd5edfa1662354ccd/cryptography-43.0.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27e613d7077ac613e399270253259d9d53872aaf657471473ebfc9a52935c062", size = 3794751 }, - { url = "https://files.pythonhosted.org/packages/5e/4b/39bb3c4c8cfb3e94e736b8d8859ce5c81536e91a1033b1d26770c4249000/cryptography-43.0.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68aaecc4178e90719e95298515979814bda0cbada1256a4485414860bd7ab962", size = 3981827 }, - { url = "https://files.pythonhosted.org/packages/ce/dc/1471d4d56608e1013237af334b8a4c35d53895694fbb73882d1c4fd3f55e/cryptography-43.0.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:de41fd81a41e53267cb020bb3a7212861da53a7d39f863585d13ea11049cf277", size = 3780034 }, - { url = "https://files.pythonhosted.org/packages/ad/43/7a9920135b0d5437cc2f8f529fa757431eb6a7736ddfadfdee1cc5890800/cryptography-43.0.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f98bf604c82c416bc829e490c700ca1553eafdf2912a91e23a79d97d9801372a", size = 3993407 }, - { url = "https://files.pythonhosted.org/packages/cc/42/9ab8467af6c0b76f3d9b8f01d1cf25b9c9f3f2151f4acfab888d21c55a72/cryptography-43.0.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:61ec41068b7b74268fa86e3e9e12b9f0c21fcf65434571dbb13d954bceb08042", size = 3886457 }, - { url = "https://files.pythonhosted.org/packages/a4/65/430509e31700286ec02868a2457d2111d03ccefc20349d24e58d171ae0a7/cryptography-43.0.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:014f58110f53237ace6a408b5beb6c427b64e084eb451ef25a28308270086494", size = 4081499 }, - { url = "https://files.pythonhosted.org/packages/bb/18/a04b6467e6e09df8c73b91dcee8878f4a438a43a3603dc3cd6f8003b92d8/cryptography-43.0.1-cp37-abi3-win32.whl", hash = "sha256:2bd51274dcd59f09dd952afb696bf9c61a7a49dfc764c04dd33ef7a6b502a1e2", size = 2616504 }, - { url = "https://files.pythonhosted.org/packages/cc/73/0eacbdc437202edcbdc07f3576ed8fb8b0ab79d27bf2c5d822d758a72faa/cryptography-43.0.1-cp37-abi3-win_amd64.whl", hash = "sha256:666ae11966643886c2987b3b721899d250855718d6d9ce41b521252a17985f4d", size = 3067456 }, - { url = "https://files.pythonhosted.org/packages/8a/b6/bc54b371f02cffd35ff8dc6baba88304d7cf8e83632566b4b42e00383e03/cryptography-43.0.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:ac119bb76b9faa00f48128b7f5679e1d8d437365c5d26f1c2c3f0da4ce1b553d", size = 6225263 }, - { url = "https://files.pythonhosted.org/packages/00/0e/8217e348a1fa417ec4c78cd3cdf24154f5e76fd7597343a35bd403650dfd/cryptography-43.0.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bbcce1a551e262dfbafb6e6252f1ae36a248e615ca44ba302df077a846a8806", size = 3794368 }, - { url = "https://files.pythonhosted.org/packages/3d/ed/38b6be7254d8f7251fde8054af597ee8afa14f911da67a9410a45f602fc3/cryptography-43.0.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58d4e9129985185a06d849aa6df265bdd5a74ca6e1b736a77959b498e0505b85", size = 3981750 }, - { url = "https://files.pythonhosted.org/packages/64/f3/b7946c3887cf7436f002f4cbb1e6aec77b8d299b86be48eeadfefb937c4b/cryptography-43.0.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d03a475165f3134f773d1388aeb19c2d25ba88b6a9733c5c590b9ff7bbfa2e0c", size = 3778925 }, - { url = "https://files.pythonhosted.org/packages/ac/7e/ebda4dd4ae098a0990753efbb4b50954f1d03003846b943ea85070782da7/cryptography-43.0.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:511f4273808ab590912a93ddb4e3914dfd8a388fed883361b02dea3791f292e1", size = 3993152 }, - { url = "https://files.pythonhosted.org/packages/43/f6/feebbd78a3e341e3913846a3bb2c29d0b09b1b3af1573c6baabc2533e147/cryptography-43.0.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:80eda8b3e173f0f247f711eef62be51b599b5d425c429b5d4ca6a05e9e856baa", size = 3886392 }, - { url = "https://files.pythonhosted.org/packages/bd/4c/ab0b9407d5247576290b4fd8abd06b7f51bd414f04eef0f2800675512d61/cryptography-43.0.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38926c50cff6f533f8a2dae3d7f19541432610d114a70808f0926d5aaa7121e4", size = 4082606 }, - { url = "https://files.pythonhosted.org/packages/05/36/e532a671998d6fcfdb9122da16434347a58a6bae9465e527e450e0bc60a5/cryptography-43.0.1-cp39-abi3-win32.whl", hash = "sha256:a575913fb06e05e6b4b814d7f7468c2c660e8bb16d8d5a1faf9b33ccc569dd47", size = 2617948 }, - { url = "https://files.pythonhosted.org/packages/b3/c6/c09cee6968add5ff868525c3815e5dccc0e3c6e89eec58dc9135d3c40e88/cryptography-43.0.1-cp39-abi3-win_amd64.whl", hash = "sha256:d75601ad10b059ec832e78823b348bfa1a59f6b8d545db3a24fd44362a1564cb", size = 3070445 }, - { url = "https://files.pythonhosted.org/packages/18/23/4175dcd935e1649865e1af7bd0b827cc9d9769a586dcc84f7cbe96839086/cryptography-43.0.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ea25acb556320250756e53f9e20a4177515f012c9eaea17eb7587a8c4d8ae034", size = 3152694 }, - { url = "https://files.pythonhosted.org/packages/ea/45/967da50269954b993d4484bf85026c7377bd551651ebdabba94905972556/cryptography-43.0.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c1332724be35d23a854994ff0b66530119500b6053d0bd3363265f7e5e77288d", size = 3713077 }, - { url = "https://files.pythonhosted.org/packages/df/e6/ccd29a1f9a6b71294e1e9f530c4d779d5dd37c8bb736c05d5fb6d98a971b/cryptography-43.0.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fba1007b3ef89946dbbb515aeeb41e30203b004f0b4b00e5e16078b518563289", size = 3915597 }, - { url = "https://files.pythonhosted.org/packages/a2/80/fb7d668f1be5e4443b7ac191f68390be24f7c2ebd36011741f62c7645eb2/cryptography-43.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5b43d1ea6b378b54a1dc99dd8a2b5be47658fe9a7ce0a58ff0b55f4b43ef2b84", size = 2989208 }, - { url = "https://files.pythonhosted.org/packages/b2/aa/782e42ccf854943dfce72fb94a8d62220f22084ff07076a638bc3f34f3cc/cryptography-43.0.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:88cce104c36870d70c49c7c8fd22885875d950d9ee6ab54df2745f83ba0dc365", size = 3154685 }, - { url = "https://files.pythonhosted.org/packages/3e/fd/70f3e849ad4d6cca2118ee6938e0b52326d02406f10912356151dd4b6868/cryptography-43.0.1-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:9d3cdb25fa98afdd3d0892d132b8d7139e2c087da1712041f6b762e4f807cc96", size = 3713909 }, - { url = "https://files.pythonhosted.org/packages/21/b0/4ecefa99519eaa32af49a3ad002bb3e795f9e6eb32221fd87736247fa3cb/cryptography-43.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e710bf40870f4db63c3d7d929aa9e09e4e7ee219e703f949ec4073b4294f6172", size = 3916544 }, - { url = "https://files.pythonhosted.org/packages/8c/42/2948dd87b237565c77b28b674d972c7f983ffa3977dc8b8ad0736f6a7d97/cryptography-43.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7c05650fe8023c5ed0d46793d4b7d7e6cd9c04e68eabe5b0aeea836e37bdcec2", size = 2989774 }, +sdist = { url = "https://files.pythonhosted.org/packages/0d/05/07b55d1fa21ac18c3a8c79f764e2514e6f6a9698f1be44994f5adf0d29db/cryptography-43.0.3.tar.gz", hash = "sha256:315b9001266a492a6ff443b61238f956b214dbec9910a081ba5b6646a055a805", size = 686989 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1f/f3/01fdf26701a26f4b4dbc337a26883ad5bccaa6f1bbbdd29cd89e22f18a1c/cryptography-43.0.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:bf7a1932ac4176486eab36a19ed4c0492da5d97123f1406cf15e41b05e787d2e", size = 6225303 }, + { url = "https://files.pythonhosted.org/packages/a3/01/4896f3d1b392025d4fcbecf40fdea92d3df8662123f6835d0af828d148fd/cryptography-43.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63efa177ff54aec6e1c0aefaa1a241232dcd37413835a9b674b6e3f0ae2bfd3e", size = 3760905 }, + { url = "https://files.pythonhosted.org/packages/0a/be/f9a1f673f0ed4b7f6c643164e513dbad28dd4f2dcdf5715004f172ef24b6/cryptography-43.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e1ce50266f4f70bf41a2c6dc4358afadae90e2a1e5342d3c08883df1675374f", size = 3977271 }, + { url = "https://files.pythonhosted.org/packages/4e/49/80c3a7b5514d1b416d7350830e8c422a4d667b6d9b16a9392ebfd4a5388a/cryptography-43.0.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:443c4a81bb10daed9a8f334365fe52542771f25aedaf889fd323a853ce7377d6", size = 3746606 }, + { url = "https://files.pythonhosted.org/packages/0e/16/a28ddf78ac6e7e3f25ebcef69ab15c2c6be5ff9743dd0709a69a4f968472/cryptography-43.0.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:74f57f24754fe349223792466a709f8e0c093205ff0dca557af51072ff47ab18", size = 3986484 }, + { url = "https://files.pythonhosted.org/packages/01/f5/69ae8da70c19864a32b0315049866c4d411cce423ec169993d0434218762/cryptography-43.0.3-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9762ea51a8fc2a88b70cf2995e5675b38d93bf36bd67d91721c309df184f49bd", size = 3852131 }, + { url = "https://files.pythonhosted.org/packages/fd/db/e74911d95c040f9afd3612b1f732e52b3e517cb80de8bf183be0b7d413c6/cryptography-43.0.3-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:81ef806b1fef6b06dcebad789f988d3b37ccaee225695cf3e07648eee0fc6b73", size = 4075647 }, + { url = "https://files.pythonhosted.org/packages/56/48/7b6b190f1462818b324e674fa20d1d5ef3e24f2328675b9b16189cbf0b3c/cryptography-43.0.3-cp37-abi3-win32.whl", hash = "sha256:cbeb489927bd7af4aa98d4b261af9a5bc025bd87f0e3547e11584be9e9427be2", size = 2623873 }, + { url = "https://files.pythonhosted.org/packages/eb/b1/0ebff61a004f7f89e7b65ca95f2f2375679d43d0290672f7713ee3162aff/cryptography-43.0.3-cp37-abi3-win_amd64.whl", hash = "sha256:f46304d6f0c6ab8e52770addfa2fc41e6629495548862279641972b6215451cd", size = 3068039 }, + { url = "https://files.pythonhosted.org/packages/30/d5/c8b32c047e2e81dd172138f772e81d852c51f0f2ad2ae8a24f1122e9e9a7/cryptography-43.0.3-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:8ac43ae87929a5982f5948ceda07001ee5e83227fd69cf55b109144938d96984", size = 6222984 }, + { url = "https://files.pythonhosted.org/packages/2f/78/55356eb9075d0be6e81b59f45c7b48df87f76a20e73893872170471f3ee8/cryptography-43.0.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:846da004a5804145a5f441b8530b4bf35afbf7da70f82409f151695b127213d5", size = 3762968 }, + { url = "https://files.pythonhosted.org/packages/2a/2c/488776a3dc843f95f86d2f957ca0fc3407d0242b50bede7fad1e339be03f/cryptography-43.0.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f996e7268af62598f2fc1204afa98a3b5712313a55c4c9d434aef49cadc91d4", size = 3977754 }, + { url = "https://files.pythonhosted.org/packages/7c/04/2345ca92f7a22f601a9c62961741ef7dd0127c39f7310dffa0041c80f16f/cryptography-43.0.3-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:f7b178f11ed3664fd0e995a47ed2b5ff0a12d893e41dd0494f406d1cf555cab7", size = 3749458 }, + { url = "https://files.pythonhosted.org/packages/ac/25/e715fa0bc24ac2114ed69da33adf451a38abb6f3f24ec207908112e9ba53/cryptography-43.0.3-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:c2e6fc39c4ab499049df3bdf567f768a723a5e8464816e8f009f121a5a9f4405", size = 3988220 }, + { url = "https://files.pythonhosted.org/packages/21/ce/b9c9ff56c7164d8e2edfb6c9305045fbc0df4508ccfdb13ee66eb8c95b0e/cryptography-43.0.3-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e1be4655c7ef6e1bbe6b5d0403526601323420bcf414598955968c9ef3eb7d16", size = 3853898 }, + { url = "https://files.pythonhosted.org/packages/2a/33/b3682992ab2e9476b9c81fff22f02c8b0a1e6e1d49ee1750a67d85fd7ed2/cryptography-43.0.3-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:df6b6c6d742395dd77a23ea3728ab62f98379eff8fb61be2744d4679ab678f73", size = 4076592 }, + { url = "https://files.pythonhosted.org/packages/81/1e/ffcc41b3cebd64ca90b28fd58141c5f68c83d48563c88333ab660e002cd3/cryptography-43.0.3-cp39-abi3-win32.whl", hash = "sha256:d56e96520b1020449bbace2b78b603442e7e378a9b3bd68de65c782db1507995", size = 2623145 }, + { url = "https://files.pythonhosted.org/packages/87/5c/3dab83cc4aba1f4b0e733e3f0c3e7d4386440d660ba5b1e3ff995feb734d/cryptography-43.0.3-cp39-abi3-win_amd64.whl", hash = "sha256:0c580952eef9bf68c4747774cde7ec1d85a6e61de97281f2dba83c7d2c806362", size = 3068026 }, + { url = "https://files.pythonhosted.org/packages/6f/db/d8b8a039483f25fc3b70c90bc8f3e1d4497a99358d610c5067bf3bd4f0af/cryptography-43.0.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d03b5621a135bffecad2c73e9f4deb1a0f977b9a8ffe6f8e002bf6c9d07b918c", size = 3144545 }, + { url = "https://files.pythonhosted.org/packages/93/90/116edd5f8ec23b2dc879f7a42443e073cdad22950d3c8ee834e3b8124543/cryptography-43.0.3-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:a2a431ee15799d6db9fe80c82b055bae5a752bef645bba795e8e52687c69efe3", size = 3679828 }, + { url = "https://files.pythonhosted.org/packages/d8/32/1e1d78b316aa22c0ba6493cc271c1c309969e5aa5c22c830a1d7ce3471e6/cryptography-43.0.3-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:281c945d0e28c92ca5e5930664c1cefd85efe80e5c0d2bc58dd63383fda29f83", size = 3908132 }, + { url = "https://files.pythonhosted.org/packages/91/bb/cd2c13be3332e7af3cdf16154147952d39075b9f61ea5e6b5241bf4bf436/cryptography-43.0.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:f18c716be16bc1fea8e95def49edf46b82fccaa88587a45f8dc0ff6ab5d8e0a7", size = 2988811 }, + { url = "https://files.pythonhosted.org/packages/cc/fc/ff7c76afdc4f5933b5e99092528d4783d3d1b131960fc8b31eb38e076ca8/cryptography-43.0.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:4a02ded6cd4f0a5562a8887df8b3bd14e822a90f97ac5e544c162899bc467664", size = 3146844 }, + { url = "https://files.pythonhosted.org/packages/d7/29/a233efb3e98b13d9175dcb3c3146988ec990896c8fa07e8467cce27d5a80/cryptography-43.0.3-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:53a583b6637ab4c4e3591a15bc9db855b8d9dee9a669b550f311480acab6eb08", size = 3681997 }, + { url = "https://files.pythonhosted.org/packages/c0/cf/c9eea7791b961f279fb6db86c3355cfad29a73141f46427af71852b23b95/cryptography-43.0.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1ec0bcf7e17c0c5669d881b1cd38c4972fade441b27bda1051665faaa89bdcaa", size = 3905208 }, + { url = "https://files.pythonhosted.org/packages/21/ea/6c38ca546d5b6dab3874c2b8fc6b1739baac29bacdea31a8c6c0513b3cfa/cryptography-43.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2ce6fae5bdad59577b44e4dfed356944fbf1d925269114c28be377692643b4ff", size = 2989787 }, ] [[package]] @@ -656,7 +656,7 @@ dependencies = [ { name = "pyyaml" }, ] -[package.dev-dependencies] +[package.dependency-groups] dev = [ { name = "ipdb" }, { name = "ipython" }, @@ -672,7 +672,7 @@ requires-dist = [ { name = "pyyaml" }, ] -[package.metadata.requires-dev] +[package.metadata.dependency-groups] dev = [ { name = "ipdb", specifier = ">=0.13.13" }, { name = "ipython", specifier = ">=8.12.3" }, @@ -727,7 +727,6 @@ version = "1.0.80" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "openshift-python-wrapper" }, - { name = "pytest" }, { name = "pytest-testconfig" }, { name = "pyyaml" }, ] @@ -956,16 +955,16 @@ wheels = [ [[package]] name = "python-benedict" -version = "0.33.2" +version = "0.34.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "python-fsutil" }, { name = "python-slugify" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/57/63/a3d1de78d75b28e9105c236565b9f0366e009abb489a5acb09911fcf5768/python-benedict-0.33.2.tar.gz", hash = "sha256:662de43bffb4e127da2056447f8ddd7f6f5c89b72dd66d289cf9abd1cc2720c8", size = 53224 } +sdist = { url = "https://files.pythonhosted.org/packages/7a/55/a16714b67dc05773722766b81495379279a2e65b9aa613701fe1c6832a90/python_benedict-0.34.0.tar.gz", hash = "sha256:d26a59abf418400dea39785d1336f5958fd7f00a732d5cc4e0e233a94e0b2c70", size = 53249 } wheels = [ - { url = "https://files.pythonhosted.org/packages/68/5f/e32644b743d33142c6c43af50c86c6a5f535c3b3fa5b50c92aecded37741/python_benedict-0.33.2-py3-none-any.whl", hash = "sha256:50a69b601b34d4ad7b67fe94e3266ec05046bc547a4132fe43fd8fbd41aeefaa", size = 51285 }, + { url = "https://files.pythonhosted.org/packages/ea/06/dad5bf034c5cc1ec4ff4de555a0a60030b007654b20579eb5bbfa5cd2171/python_benedict-0.34.0-py3-none-any.whl", hash = "sha256:acdcd993ecf56640a3bcd935086e1c19482271950933995511d1fd16a5954ece", size = 51280 }, ] [[package]] @@ -1112,16 +1111,16 @@ wheels = [ [[package]] name = "rich" -version = "13.9.2" +version = "13.9.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markdown-it-py" }, { name = "pygments" }, { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/aa/9e/1784d15b057b0075e5136445aaea92d23955aad2c93eaede673718a40d95/rich-13.9.2.tar.gz", hash = "sha256:51a2c62057461aaf7152b4d611168f93a9fc73068f8ded2790f29fe2b5366d0c", size = 222843 } +sdist = { url = "https://files.pythonhosted.org/packages/d9/e9/cf9ef5245d835065e6673781dbd4b8911d352fb770d56cf0879cf11b7ee1/rich-13.9.3.tar.gz", hash = "sha256:bc1e01b899537598cf02579d2b9f4a415104d3fc439313a7a2c165d76557a08e", size = 222889 } wheels = [ - { url = "https://files.pythonhosted.org/packages/67/91/5474b84e505a6ccc295b2d322d90ff6aa0746745717839ee0c5fb4fdcceb/rich-13.9.2-py3-none-any.whl", hash = "sha256:8c82a3d3f8dcfe9e734771313e606b39d8247bb6b826e196f4914b333b743cf1", size = 242117 }, + { url = "https://files.pythonhosted.org/packages/9a/e2/10e9819cf4a20bd8ea2f5dabafc2e6bf4a78d6a0965daeb60a4b34d1c11f/rich-13.9.3-py3-none-any.whl", hash = "sha256:9836f5096eb2172c9e77df411c1b009bace4193d6a481d534fea75ebba758283", size = 242157 }, ] [[package]] @@ -1138,27 +1137,27 @@ wheels = [ [[package]] name = "ruff" -version = "0.6.9" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/26/0d/6148a48dab5662ca1d5a93b7c0d13c03abd3cc7e2f35db08410e47cef15d/ruff-0.6.9.tar.gz", hash = "sha256:b076ef717a8e5bc819514ee1d602bbdca5b4420ae13a9cf61a0c0a4f53a2baa2", size = 3095355 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6e/8f/f7a0a0ef1818662efb32ed6df16078c95da7a0a3248d64c2410c1e27799f/ruff-0.6.9-py3-none-linux_armv6l.whl", hash = "sha256:064df58d84ccc0ac0fcd63bc3090b251d90e2a372558c0f057c3f75ed73e1ccd", size = 10440526 }, - { url = "https://files.pythonhosted.org/packages/8b/69/b179a5faf936a9e2ab45bb412a668e4661eded964ccfa19d533f29463ef6/ruff-0.6.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:140d4b5c9f5fc7a7b074908a78ab8d384dd7f6510402267bc76c37195c02a7ec", size = 10034612 }, - { url = "https://files.pythonhosted.org/packages/c7/ef/fd1b4be979c579d191eeac37b5cfc0ec906de72c8bcd8595e2c81bb700c1/ruff-0.6.9-py3-none-macosx_11_0_arm64.whl", hash = "sha256:53fd8ca5e82bdee8da7f506d7b03a261f24cd43d090ea9db9a1dc59d9313914c", size = 9706197 }, - { url = "https://files.pythonhosted.org/packages/29/61/b376d775deb5851cb48d893c568b511a6d3625ef2c129ad5698b64fb523c/ruff-0.6.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:645d7d8761f915e48a00d4ecc3686969761df69fb561dd914a773c1a8266e14e", size = 10751855 }, - { url = "https://files.pythonhosted.org/packages/13/d7/def9e5f446d75b9a9c19b24231a3a658c075d79163b08582e56fa5dcfa38/ruff-0.6.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eae02b700763e3847595b9d2891488989cac00214da7f845f4bcf2989007d577", size = 10200889 }, - { url = "https://files.pythonhosted.org/packages/6c/d6/7f34160818bcb6e84ce293a5966cba368d9112ff0289b273fbb689046047/ruff-0.6.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d5ccc9e58112441de8ad4b29dcb7a86dc25c5f770e3c06a9d57e0e5eba48829", size = 11038678 }, - { url = "https://files.pythonhosted.org/packages/13/34/a40ff8ae62fb1b26fb8e6fa7e64bc0e0a834b47317880de22edd6bfb54fb/ruff-0.6.9-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:417b81aa1c9b60b2f8edc463c58363075412866ae4e2b9ab0f690dc1e87ac1b5", size = 11808682 }, - { url = "https://files.pythonhosted.org/packages/2e/6d/25a4386ae4009fc798bd10ba48c942d1b0b3e459b5403028f1214b6dd161/ruff-0.6.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3c866b631f5fbce896a74a6e4383407ba7507b815ccc52bcedabb6810fdb3ef7", size = 11330446 }, - { url = "https://files.pythonhosted.org/packages/f7/f6/bdf891a9200d692c94ebcd06ae5a2fa5894e522f2c66c2a12dd5d8cb2654/ruff-0.6.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7b118afbb3202f5911486ad52da86d1d52305b59e7ef2031cea3425142b97d6f", size = 12483048 }, - { url = "https://files.pythonhosted.org/packages/a7/86/96f4252f41840e325b3fa6c48297e661abb9f564bd7dcc0572398c8daa42/ruff-0.6.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a67267654edc23c97335586774790cde402fb6bbdb3c2314f1fc087dee320bfa", size = 10936855 }, - { url = "https://files.pythonhosted.org/packages/45/87/801a52d26c8dbf73424238e9908b9ceac430d903c8ef35eab1b44fcfa2bd/ruff-0.6.9-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3ef0cc774b00fec123f635ce5c547dac263f6ee9fb9cc83437c5904183b55ceb", size = 10713007 }, - { url = "https://files.pythonhosted.org/packages/be/27/6f7161d90320a389695e32b6ebdbfbedde28ccbf52451e4b723d7ce744ad/ruff-0.6.9-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:12edd2af0c60fa61ff31cefb90aef4288ac4d372b4962c2864aeea3a1a2460c0", size = 10274594 }, - { url = "https://files.pythonhosted.org/packages/00/52/dc311775e7b5f5b19831563cb1572ecce63e62681bccc609867711fae317/ruff-0.6.9-py3-none-musllinux_1_2_i686.whl", hash = "sha256:55bb01caeaf3a60b2b2bba07308a02fca6ab56233302406ed5245180a05c5625", size = 10608024 }, - { url = "https://files.pythonhosted.org/packages/98/b6/be0a1ddcbac65a30c985cf7224c4fce786ba2c51e7efeb5178fe410ed3cf/ruff-0.6.9-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:925d26471fa24b0ce5a6cdfab1bb526fb4159952385f386bdcc643813d472039", size = 10982085 }, - { url = "https://files.pythonhosted.org/packages/bb/a4/c84bc13d0b573cf7bb7d17b16d6d29f84267c92d79b2f478d4ce322e8e72/ruff-0.6.9-py3-none-win32.whl", hash = "sha256:eb61ec9bdb2506cffd492e05ac40e5bc6284873aceb605503d8494180d6fc84d", size = 8522088 }, - { url = "https://files.pythonhosted.org/packages/74/be/fc352bd8ca40daae8740b54c1c3e905a7efe470d420a268cd62150248c91/ruff-0.6.9-py3-none-win_amd64.whl", hash = "sha256:785d31851c1ae91f45b3d8fe23b8ae4b5170089021fbb42402d811135f0b7117", size = 9359275 }, - { url = "https://files.pythonhosted.org/packages/3e/14/fd026bc74ded05e2351681545a5f626e78ef831f8edce064d61acd2e6ec7/ruff-0.6.9-py3-none-win_arm64.whl", hash = "sha256:a9641e31476d601f83cd602608739a0840e348bda93fec9f1ee816f8b6798b93", size = 8679879 }, +version = "0.7.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a6/21/5c6e05e0fd3fbb41be4fb92edbc9a04de70baf60adb61435ce0c6b8c3d55/ruff-0.7.1.tar.gz", hash = "sha256:9d8a41d4aa2dad1575adb98a82870cf5db5f76b2938cf2206c22c940034a36f4", size = 3181670 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/65/45/8a20a9920175c9c4892b2420f80ff3cf14949cf3067118e212f9acd9c908/ruff-0.7.1-py3-none-linux_armv6l.whl", hash = "sha256:cb1bc5ed9403daa7da05475d615739cc0212e861b7306f314379d958592aaa89", size = 10389268 }, + { url = "https://files.pythonhosted.org/packages/1b/d3/2f8382db2cf4f9488e938602e33e36287f9d26cb283aa31f11c31297ce79/ruff-0.7.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:27c1c52a8d199a257ff1e5582d078eab7145129aa02721815ca8fa4f9612dc35", size = 10188348 }, + { url = "https://files.pythonhosted.org/packages/a2/31/7d14e2a88da351200f844b7be889a0845d9e797162cf76b136d21b832a23/ruff-0.7.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:588a34e1ef2ea55b4ddfec26bbe76bc866e92523d8c6cdec5e8aceefeff02d99", size = 9841448 }, + { url = "https://files.pythonhosted.org/packages/db/99/738cafdc768eceeca0bd26c6f03e213aa91203d2278e1d95b1c31c4ece41/ruff-0.7.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94fc32f9cdf72dc75c451e5f072758b118ab8100727168a3df58502b43a599ca", size = 10674864 }, + { url = "https://files.pythonhosted.org/packages/fe/12/bcf2836b50eab53c65008383e7d55201e490d75167c474f14a16e1af47d2/ruff-0.7.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:985818742b833bffa543a84d1cc11b5e6871de1b4e0ac3060a59a2bae3969250", size = 10192105 }, + { url = "https://files.pythonhosted.org/packages/2b/71/261d5d668bf98b6c44e89bfb5dfa4cb8cb6c8b490a201a3d8030e136ea4f/ruff-0.7.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:32f1e8a192e261366c702c5fb2ece9f68d26625f198a25c408861c16dc2dea9c", size = 11194144 }, + { url = "https://files.pythonhosted.org/packages/90/1f/0926d18a3b566fa6e7b3b36093088e4ffef6b6ba4ea85a462d9a93f7e35c/ruff-0.7.1-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:699085bf05819588551b11751eff33e9ca58b1b86a6843e1b082a7de40da1565", size = 11917066 }, + { url = "https://files.pythonhosted.org/packages/cd/a8/9fac41f128b6a44ab4409c1493430b4ee4b11521e8aeeca19bfe1ce851f9/ruff-0.7.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:344cc2b0814047dc8c3a8ff2cd1f3d808bb23c6658db830d25147339d9bf9ea7", size = 11458821 }, + { url = "https://files.pythonhosted.org/packages/25/cd/59644168f086ab13fe4e02943b9489a0aa710171f66b178e179df5383554/ruff-0.7.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4316bbf69d5a859cc937890c7ac7a6551252b6a01b1d2c97e8fc96e45a7c8b4a", size = 12700379 }, + { url = "https://files.pythonhosted.org/packages/fb/30/3bac63619eb97174661829c07fc46b2055a053dee72da29d7c304c1cd2c0/ruff-0.7.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:79d3af9dca4c56043e738a4d6dd1e9444b6d6c10598ac52d146e331eb155a8ad", size = 11019813 }, + { url = "https://files.pythonhosted.org/packages/4b/af/f567b885b5cb3bcdbcca3458ebf210cc8c9c7a9f61c332d3c2a050c3b21e/ruff-0.7.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:c5c121b46abde94a505175524e51891f829414e093cd8326d6e741ecfc0a9112", size = 10662146 }, + { url = "https://files.pythonhosted.org/packages/bc/ad/eb930d3ad117a9f2f7261969c21559ebd82bb13b6e8001c7caed0d44be5f/ruff-0.7.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8422104078324ea250886954e48f1373a8fe7de59283d747c3a7eca050b4e378", size = 10256911 }, + { url = "https://files.pythonhosted.org/packages/20/d5/af292ce70a016fcec792105ca67f768b403dd480a11888bc1f418fed0dd5/ruff-0.7.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:56aad830af8a9db644e80098fe4984a948e2b6fc2e73891538f43bbe478461b8", size = 10767488 }, + { url = "https://files.pythonhosted.org/packages/24/85/cc04a3bd027f433bebd2a097e63b3167653c079f7f13d8f9a1178e693412/ruff-0.7.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:658304f02f68d3a83c998ad8bf91f9b4f53e93e5412b8f2388359d55869727fd", size = 11093368 }, + { url = "https://files.pythonhosted.org/packages/0b/fb/c39cbf32d1f3e318674b8622f989417231794926b573f76dd4d0ca49f0f1/ruff-0.7.1-py3-none-win32.whl", hash = "sha256:b517a2011333eb7ce2d402652ecaa0ac1a30c114fbbd55c6b8ee466a7f600ee9", size = 8594180 }, + { url = "https://files.pythonhosted.org/packages/5a/71/ec8cdea34ecb90c830ca60d54ac7b509a7b5eab50fae27e001d4470fe813/ruff-0.7.1-py3-none-win_amd64.whl", hash = "sha256:f38c41fcde1728736b4eb2b18850f6d1e3eedd9678c914dede554a70d5241307", size = 9419751 }, + { url = "https://files.pythonhosted.org/packages/79/7b/884553415e9f0a9bf358ed52fb68b934e67ef6c5a62397ace924a1afdf9a/ruff-0.7.1-py3-none-win_arm64.whl", hash = "sha256:19aa200ec824c0f36d0c9114c8ec0087082021732979a359d6f3c390a6ff2a37", size = 8717402 }, ] [[package]] From e8f8f360a5bf2678c841cb7f0b4ea6b492bffff6 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 29 Oct 2024 06:21:04 +0200 Subject: [PATCH 09/31] [pre-commit.ci] pre-commit autoupdate (#29) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [pre-commit.ci] pre-commit autoupdate updates: - [github.com/astral-sh/ruff-pre-commit: v0.7.0 → v0.7.1](https://github.com/astral-sh/ruff-pre-commit/compare/v0.7.0...v0.7.1) - [github.com/renovatebot/pre-commit-hooks: 38.129.0 → 38.133.1](https://github.com/renovatebot/pre-commit-hooks/compare/38.129.0...38.133.1) - [github.com/gitleaks/gitleaks: v8.21.1 → v8.21.2](https://github.com/gitleaks/gitleaks/compare/v8.21.1...v8.21.2) - [github.com/pre-commit/mirrors-mypy: v1.12.1 → v1.13.0](https://github.com/pre-commit/mirrors-mypy/compare/v1.12.1...v1.13.0) * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 8 ++++---- .../storage/pvc/test_kserve_pvc_write_access.py | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1d60c41..04a5f8b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -34,23 +34,23 @@ repos: - id: detect-secrets - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.7.0 + rev: v0.7.1 hooks: - id: ruff - id: ruff-format - repo: https://github.com/renovatebot/pre-commit-hooks - rev: 38.129.0 + rev: 38.133.1 hooks: - id: renovate-config-validator - repo: https://github.com/gitleaks/gitleaks - rev: v8.21.1 + rev: v8.21.2 hooks: - id: gitleaks - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.12.1 + rev: v1.13.0 hooks: - id: mypy additional_dependencies: ["types-PyYAML"] diff --git a/tests/model_serving/model_server/storage/pvc/test_kserve_pvc_write_access.py b/tests/model_serving/model_server/storage/pvc/test_kserve_pvc_write_access.py index b28ed97..f0ac9ce 100644 --- a/tests/model_serving/model_server/storage/pvc/test_kserve_pvc_write_access.py +++ b/tests/model_serving/model_server/storage/pvc/test_kserve_pvc_write_access.py @@ -39,9 +39,9 @@ def test_pod_containers_not_restarted(self, first_predictor_pod): assert not restarted_containers, f"Containers {restarted_containers} restarted" def test_isvc_read_only_annotation_not_set_by_default(self, inference_service): - assert not inference_service.instance.metadata.annotations.get( - "storage.kserve.io/readonly" - ), "Read only annotation is set" + assert not inference_service.instance.metadata.annotations.get("storage.kserve.io/readonly"), ( + "Read only annotation is set" + ) def test_isvc_read_only_annotation_default_value(self, first_predictor_pod): with pytest.raises(ExecOnPodError): From 0895f325fb3208d537b8d6c0b139f41e43548889 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 5 Nov 2024 14:24:11 +0200 Subject: [PATCH 10/31] [pre-commit.ci] pre-commit autoupdate (#32) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.7.1 → v0.7.2](https://github.com/astral-sh/ruff-pre-commit/compare/v0.7.1...v0.7.2) - [github.com/renovatebot/pre-commit-hooks: 38.133.1 → 39.0.0](https://github.com/renovatebot/pre-commit-hooks/compare/38.133.1...39.0.0) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 04a5f8b..dbce7f8 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -34,13 +34,13 @@ repos: - id: detect-secrets - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.7.1 + rev: v0.7.2 hooks: - id: ruff - id: ruff-format - repo: https://github.com/renovatebot/pre-commit-hooks - rev: 38.133.1 + rev: 39.0.0 hooks: - id: renovate-config-validator From bd1b606db751aba6be17ccfa802b8435281c4756 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 5 Nov 2024 14:25:31 +0200 Subject: [PATCH 11/31] Lock file maintenance (#31) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- uv.lock | 66 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/uv.lock b/uv.lock index baf86d5..c8b48f1 100644 --- a/uv.lock +++ b/uv.lock @@ -311,14 +311,14 @@ wheels = [ [[package]] name = "colorlog" -version = "6.8.2" +version = "6.9.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/db/38/2992ff192eaa7dd5a793f8b6570d6bbe887c4fbbf7e72702eb0a693a01c8/colorlog-6.8.2.tar.gz", hash = "sha256:3e3e079a41feb5a1b64f978b5ea4f46040a94f11f0e8bbb8261e3dbbeca64d44", size = 16529 } +sdist = { url = "https://files.pythonhosted.org/packages/d3/7a/359f4d5df2353f26172b3cc39ea32daa39af8de522205f512f458923e677/colorlog-6.9.0.tar.gz", hash = "sha256:bfba54a1b93b94f54e1f4fe48395725a3d92fd2a4af702f6bd70946bdc0c6ac2", size = 16624 } wheels = [ - { url = "https://files.pythonhosted.org/packages/f3/18/3e867ab37a24fdf073c1617b9c7830e06ec270b1ea4694a624038fc40a03/colorlog-6.8.2-py3-none-any.whl", hash = "sha256:4dcbb62368e2800cb3c5abd348da7e53f6c362dda502ec27c560b2e58a66bd33", size = 11357 }, + { url = "https://files.pythonhosted.org/packages/e3/51/9b208e85196941db2f0654ad0357ca6388ab3ed67efdbfc799f35d1f83aa/colorlog-6.9.0-py3-none-any.whl", hash = "sha256:5906e71acd67cb07a71e779c47c4bcb45fb8c2993eebe9e5adcd6a6f1b283eff", size = 11424 }, ] [[package]] @@ -656,7 +656,7 @@ dependencies = [ { name = "pyyaml" }, ] -[package.dependency-groups] +[package.dev-dependencies] dev = [ { name = "ipdb" }, { name = "ipython" }, @@ -672,7 +672,7 @@ requires-dist = [ { name = "pyyaml" }, ] -[package.metadata.dependency-groups] +[package.metadata.requires-dev] dev = [ { name = "ipdb", specifier = ">=0.13.13" }, { name = "ipython", specifier = ">=8.12.3" }, @@ -680,7 +680,7 @@ dev = [ [[package]] name = "openshift-python-utilities" -version = "5.0.70" +version = "5.0.73" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "beautifulsoup4" }, @@ -695,11 +695,11 @@ dependencies = [ { name = "semver" }, { name = "timeout-sampler" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a4/72/fa3d90605f10621b2b3409c400ca7230c36ec4ca1b549f74829c196451e1/openshift_python_utilities-5.0.70.tar.gz", hash = "sha256:dcc8e31f263f04584cda6e327415e72ac00f5a563e7eecbd401b0cc9a6abc382", size = 18300 } +sdist = { url = "https://files.pythonhosted.org/packages/81/83/aaba0e774e90612814c105a9badc57f65b996c82c5f857564a6497c3b8af/openshift_python_utilities-5.0.73.tar.gz", hash = "sha256:56ef35996b6f46f4589442bcc52074a536ed3c2625b8acdad58df50906369588", size = 18369 } [[package]] name = "openshift-python-wrapper" -version = "10.0.99" +version = "10.0.107" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, @@ -719,7 +719,7 @@ dependencies = [ { name = "timeout-sampler" }, { name = "xmltodict" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7c/28/ae14f46ee41e83d977a2bc1b52022407cbbd8bafa70992a47c9eda168c44/openshift_python_wrapper-10.0.99.tar.gz", hash = "sha256:c7c59b035532ab5447a0f6b2b83eb340042c309f74dd6bf7f3fee52b83a4417d", size = 6748161 } +sdist = { url = "https://files.pythonhosted.org/packages/1b/9c/9a8fd01a6b64665e648063acf0b296f2eb42d33076ef259ca69e06482359/openshift_python_wrapper-10.0.107.tar.gz", hash = "sha256:cee14a41a892e5a367039a4be986baf7ba3938dcc83c72ee73d9e59be8b6528c", size = 4531673 } [[package]] name = "openshift-python-wrapper-data-collector" @@ -1111,16 +1111,16 @@ wheels = [ [[package]] name = "rich" -version = "13.9.3" +version = "13.9.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markdown-it-py" }, { name = "pygments" }, { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d9/e9/cf9ef5245d835065e6673781dbd4b8911d352fb770d56cf0879cf11b7ee1/rich-13.9.3.tar.gz", hash = "sha256:bc1e01b899537598cf02579d2b9f4a415104d3fc439313a7a2c165d76557a08e", size = 222889 } +sdist = { url = "https://files.pythonhosted.org/packages/ab/3a/0316b28d0761c6734d6bc14e770d85506c986c85ffb239e688eeaab2c2bc/rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098", size = 223149 } wheels = [ - { url = "https://files.pythonhosted.org/packages/9a/e2/10e9819cf4a20bd8ea2f5dabafc2e6bf4a78d6a0965daeb60a4b34d1c11f/rich-13.9.3-py3-none-any.whl", hash = "sha256:9836f5096eb2172c9e77df411c1b009bace4193d6a481d534fea75ebba758283", size = 242157 }, + { url = "https://files.pythonhosted.org/packages/19/71/39c7c0d87f8d4e6c020a393182060eaefeeae6c01dab6a84ec346f2567df/rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90", size = 242424 }, ] [[package]] @@ -1137,27 +1137,27 @@ wheels = [ [[package]] name = "ruff" -version = "0.7.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a6/21/5c6e05e0fd3fbb41be4fb92edbc9a04de70baf60adb61435ce0c6b8c3d55/ruff-0.7.1.tar.gz", hash = "sha256:9d8a41d4aa2dad1575adb98a82870cf5db5f76b2938cf2206c22c940034a36f4", size = 3181670 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/65/45/8a20a9920175c9c4892b2420f80ff3cf14949cf3067118e212f9acd9c908/ruff-0.7.1-py3-none-linux_armv6l.whl", hash = "sha256:cb1bc5ed9403daa7da05475d615739cc0212e861b7306f314379d958592aaa89", size = 10389268 }, - { url = "https://files.pythonhosted.org/packages/1b/d3/2f8382db2cf4f9488e938602e33e36287f9d26cb283aa31f11c31297ce79/ruff-0.7.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:27c1c52a8d199a257ff1e5582d078eab7145129aa02721815ca8fa4f9612dc35", size = 10188348 }, - { url = "https://files.pythonhosted.org/packages/a2/31/7d14e2a88da351200f844b7be889a0845d9e797162cf76b136d21b832a23/ruff-0.7.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:588a34e1ef2ea55b4ddfec26bbe76bc866e92523d8c6cdec5e8aceefeff02d99", size = 9841448 }, - { url = "https://files.pythonhosted.org/packages/db/99/738cafdc768eceeca0bd26c6f03e213aa91203d2278e1d95b1c31c4ece41/ruff-0.7.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94fc32f9cdf72dc75c451e5f072758b118ab8100727168a3df58502b43a599ca", size = 10674864 }, - { url = "https://files.pythonhosted.org/packages/fe/12/bcf2836b50eab53c65008383e7d55201e490d75167c474f14a16e1af47d2/ruff-0.7.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:985818742b833bffa543a84d1cc11b5e6871de1b4e0ac3060a59a2bae3969250", size = 10192105 }, - { url = "https://files.pythonhosted.org/packages/2b/71/261d5d668bf98b6c44e89bfb5dfa4cb8cb6c8b490a201a3d8030e136ea4f/ruff-0.7.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:32f1e8a192e261366c702c5fb2ece9f68d26625f198a25c408861c16dc2dea9c", size = 11194144 }, - { url = "https://files.pythonhosted.org/packages/90/1f/0926d18a3b566fa6e7b3b36093088e4ffef6b6ba4ea85a462d9a93f7e35c/ruff-0.7.1-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:699085bf05819588551b11751eff33e9ca58b1b86a6843e1b082a7de40da1565", size = 11917066 }, - { url = "https://files.pythonhosted.org/packages/cd/a8/9fac41f128b6a44ab4409c1493430b4ee4b11521e8aeeca19bfe1ce851f9/ruff-0.7.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:344cc2b0814047dc8c3a8ff2cd1f3d808bb23c6658db830d25147339d9bf9ea7", size = 11458821 }, - { url = "https://files.pythonhosted.org/packages/25/cd/59644168f086ab13fe4e02943b9489a0aa710171f66b178e179df5383554/ruff-0.7.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4316bbf69d5a859cc937890c7ac7a6551252b6a01b1d2c97e8fc96e45a7c8b4a", size = 12700379 }, - { url = "https://files.pythonhosted.org/packages/fb/30/3bac63619eb97174661829c07fc46b2055a053dee72da29d7c304c1cd2c0/ruff-0.7.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:79d3af9dca4c56043e738a4d6dd1e9444b6d6c10598ac52d146e331eb155a8ad", size = 11019813 }, - { url = "https://files.pythonhosted.org/packages/4b/af/f567b885b5cb3bcdbcca3458ebf210cc8c9c7a9f61c332d3c2a050c3b21e/ruff-0.7.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:c5c121b46abde94a505175524e51891f829414e093cd8326d6e741ecfc0a9112", size = 10662146 }, - { url = "https://files.pythonhosted.org/packages/bc/ad/eb930d3ad117a9f2f7261969c21559ebd82bb13b6e8001c7caed0d44be5f/ruff-0.7.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8422104078324ea250886954e48f1373a8fe7de59283d747c3a7eca050b4e378", size = 10256911 }, - { url = "https://files.pythonhosted.org/packages/20/d5/af292ce70a016fcec792105ca67f768b403dd480a11888bc1f418fed0dd5/ruff-0.7.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:56aad830af8a9db644e80098fe4984a948e2b6fc2e73891538f43bbe478461b8", size = 10767488 }, - { url = "https://files.pythonhosted.org/packages/24/85/cc04a3bd027f433bebd2a097e63b3167653c079f7f13d8f9a1178e693412/ruff-0.7.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:658304f02f68d3a83c998ad8bf91f9b4f53e93e5412b8f2388359d55869727fd", size = 11093368 }, - { url = "https://files.pythonhosted.org/packages/0b/fb/c39cbf32d1f3e318674b8622f989417231794926b573f76dd4d0ca49f0f1/ruff-0.7.1-py3-none-win32.whl", hash = "sha256:b517a2011333eb7ce2d402652ecaa0ac1a30c114fbbd55c6b8ee466a7f600ee9", size = 8594180 }, - { url = "https://files.pythonhosted.org/packages/5a/71/ec8cdea34ecb90c830ca60d54ac7b509a7b5eab50fae27e001d4470fe813/ruff-0.7.1-py3-none-win_amd64.whl", hash = "sha256:f38c41fcde1728736b4eb2b18850f6d1e3eedd9678c914dede554a70d5241307", size = 9419751 }, - { url = "https://files.pythonhosted.org/packages/79/7b/884553415e9f0a9bf358ed52fb68b934e67ef6c5a62397ace924a1afdf9a/ruff-0.7.1-py3-none-win_arm64.whl", hash = "sha256:19aa200ec824c0f36d0c9114c8ec0087082021732979a359d6f3c390a6ff2a37", size = 8717402 }, +version = "0.7.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/95/51/231bb3790e5b0b9fd4131f9a231d73d061b3667522e3f406fd9b63334d0e/ruff-0.7.2.tar.gz", hash = "sha256:2b14e77293380e475b4e3a7a368e14549288ed2931fce259a6f99978669e844f", size = 3210036 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5c/56/0caa2b5745d66a39aa239c01059f6918fc76ed8380033d2f44bf297d141d/ruff-0.7.2-py3-none-linux_armv6l.whl", hash = "sha256:b73f873b5f52092e63ed540adefc3c36f1f803790ecf2590e1df8bf0a9f72cb8", size = 10373973 }, + { url = "https://files.pythonhosted.org/packages/1a/33/cad6ff306731f335d481c50caa155b69a286d5b388e87ff234cd2a4b3557/ruff-0.7.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:5b813ef26db1015953daf476202585512afd6a6862a02cde63f3bafb53d0b2d4", size = 10171140 }, + { url = "https://files.pythonhosted.org/packages/97/f5/6a2ca5c9ba416226eac9cf8121a1baa6f06655431937e85f38ffcb9d0d01/ruff-0.7.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:853277dbd9675810c6826dad7a428d52a11760744508340e66bf46f8be9701d9", size = 9809333 }, + { url = "https://files.pythonhosted.org/packages/16/83/e3e87f13d1a1dc205713632978cd7bc287a59b08bc95780dbe359b9aefcb/ruff-0.7.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21aae53ab1490a52bf4e3bf520c10ce120987b047c494cacf4edad0ba0888da2", size = 10622987 }, + { url = "https://files.pythonhosted.org/packages/22/16/97ccab194480e99a2e3c77ae132b3eebfa38c2112747570c403a4a13ba3a/ruff-0.7.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ccc7e0fc6e0cb3168443eeadb6445285abaae75142ee22b2b72c27d790ab60ba", size = 10184640 }, + { url = "https://files.pythonhosted.org/packages/97/1b/82ff05441b036f68817296c14f24da47c591cb27acfda473ee571a5651ac/ruff-0.7.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd77877a4e43b3a98e5ef4715ba3862105e299af0c48942cc6d51ba3d97dc859", size = 11210203 }, + { url = "https://files.pythonhosted.org/packages/a6/96/7ecb30a7ef7f942e2d8e0287ad4c1957dddc6c5097af4978c27cfc334f97/ruff-0.7.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:e00163fb897d35523c70d71a46fbaa43bf7bf9af0f4534c53ea5b96b2e03397b", size = 11870894 }, + { url = "https://files.pythonhosted.org/packages/06/6a/c716bb126218227f8e604a9c484836257708a05ee3d2ebceb666ff3d3867/ruff-0.7.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f3c54b538633482dc342e9b634d91168fe8cc56b30a4b4f99287f4e339103e88", size = 11449533 }, + { url = "https://files.pythonhosted.org/packages/e6/2f/3a5f9f9478904e5ae9506ea699109070ead1e79aac041e872cbaad8a7458/ruff-0.7.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7b792468e9804a204be221b14257566669d1db5c00d6bb335996e5cd7004ba80", size = 12607919 }, + { url = "https://files.pythonhosted.org/packages/a0/57/4642e57484d80d274750dcc872ea66655bbd7e66e986fede31e1865b463d/ruff-0.7.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dba53ed84ac19ae4bfb4ea4bf0172550a2285fa27fbb13e3746f04c80f7fa088", size = 11016915 }, + { url = "https://files.pythonhosted.org/packages/4d/6d/59be6680abee34c22296ae3f46b2a3b91662b8b18ab0bf388b5eb1355c97/ruff-0.7.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:b19fafe261bf741bca2764c14cbb4ee1819b67adb63ebc2db6401dcd652e3748", size = 10625424 }, + { url = "https://files.pythonhosted.org/packages/82/e7/f6a643683354c9bc7879d2f228ee0324fea66d253de49273a0814fba1927/ruff-0.7.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:28bd8220f4d8f79d590db9e2f6a0674f75ddbc3847277dd44ac1f8d30684b828", size = 10233692 }, + { url = "https://files.pythonhosted.org/packages/d7/48/b4e02fc835cd7ed1ee7318d9c53e48bcf6b66301f55925a7dcb920e45532/ruff-0.7.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:9fd67094e77efbea932e62b5d2483006154794040abb3a5072e659096415ae1e", size = 10751825 }, + { url = "https://files.pythonhosted.org/packages/1e/06/6c5ee6ab7bb4cbad9e8bb9b2dd0d818c759c90c1c9e057c6ed70334b97f4/ruff-0.7.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:576305393998b7bd6c46018f8104ea3a9cb3fa7908c21d8580e3274a3b04b691", size = 11074811 }, + { url = "https://files.pythonhosted.org/packages/a1/16/8969304f25bcd0e4af1778342e63b715e91db8a2dbb51807acd858cba915/ruff-0.7.2-py3-none-win32.whl", hash = "sha256:fa993cfc9f0ff11187e82de874dfc3611df80852540331bc85c75809c93253a8", size = 8650268 }, + { url = "https://files.pythonhosted.org/packages/d9/18/c4b00d161def43fe5968e959039c8f6ce60dca762cec4a34e4e83a4210a0/ruff-0.7.2-py3-none-win_amd64.whl", hash = "sha256:dd8800cbe0254e06b8fec585e97554047fb82c894973f7ff18558eee33d1cb88", size = 9433693 }, + { url = "https://files.pythonhosted.org/packages/7f/7b/c920673ac01c19814dd15fc617c02301c522f3d6812ca2024f4588ed4549/ruff-0.7.2-py3-none-win_arm64.whl", hash = "sha256:bb8368cd45bba3f57bb29cbb8d64b4a33f8415d0149d2655c5c8539452ce7760", size = 8735845 }, ] [[package]] From 08201c603b0a4104ea5e5a873c12fd4015333972 Mon Sep 17 00:00:00 2001 From: Ruth Netser Date: Wed, 6 Nov 2024 11:35:48 +0200 Subject: [PATCH 12/31] add CONTRIBUTING and update README (#25) --- CONTRIBUTING.md | 33 +++++++++++++++++++++++++++++++++ README.md | 48 ++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..11d6d84 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,33 @@ +# Welcome to opendatahub-tests contributing guide + +Thank you for contributing to our project! + +## New contributor guide + +To get an overview of the project, read the [README](README.md). + +## Issues + +### Create a new issue + +If you find a problem with the code, [search if an issue already exists](https://github.com/opendatahub-io/opendatahub-tests/issues). +If you open a pull request to fix the problem, an issue will ba automatically created. +If a related issue doesn't exist, you can open a new issue using a relevant [issue form](https://github.com/opendatahub-io/opendatahub-tests/issues/new/choose). + +## Pull requests + +To contribute code to the project: + +- Fork the project and work on your forked repository +- Before submitting a new pull request, make sure you have [pre-commit](https://pre-commit.com/) package and installed + +```bash +pre-commit install +``` + +- When submitting a pull request, make sure to fill all the required, relevant fields for your PR. + Make sure the title is descriptive and short. + +## General + +- Add typing to new code; typing is enforced using [mypy](https://mypy-lang.org/) diff --git a/README.md b/README.md index 41bec21..28cfbea 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,48 @@ # opendatahub-tests -# TODO: update file -# Run `pre-commit` before committing. You will need npm installed to do so. +This repository contains ODH / Red Hat Openshift AI (RHOAI) tests. + +## Contribute to opendatahub-tests +Please follow the [Contributing Guide](CONTRIBUTING.md) + +# Getting started +## Installation + +Install [uv](https://github.com/astral-sh/uv) + +## Tests cluster + +These tests can be executed against arbitrary cluster with ODH / RHOAI installed. + +You can log in into such cluster via: + +```bash +oc login -u user -p password +``` + +Or by setting `KUBECONFIG` variable: + +```bash +KUBECONFIG= +``` + +or by saving the kubeconfig file under `~/.kube/config` + +## Running the tests +### Basic run of all tests + +```bash +uv run pytest +``` + +### To overwrite a pytest config argument + +```bash +uv run pytest --tc=: +``` + +For example: + +```bash +uv run pytest --tc=ci_s3_bucket_name:my-bucket +``` From 657cf22f127d7561a26101793cd1367027d75311 Mon Sep 17 00:00:00 2001 From: Ruth Netser Date: Wed, 6 Nov 2024 12:59:50 +0200 Subject: [PATCH 13/31] Move to Python 3.9 (#33) --- pyproject.toml | 2 +- uv.lock | 43 +------------------------------------------ 2 files changed, 2 insertions(+), 43 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 9bed9b6..6ffca8a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,7 +25,7 @@ dev-dependencies = [ [tool.uv.sources] [project] -requires-python = ">=3.8" +requires-python = ">=3.9" name = "opendatahub-tests" version = "0.1.0" description = "Tests repository for Open Data Hub (ODH)" diff --git a/uv.lock b/uv.lock index c8b48f1..3d00046 100644 --- a/uv.lock +++ b/uv.lock @@ -1,5 +1,5 @@ version = 1 -requires-python = ">=3.8" +requires-python = ">=3.9" resolution-markers = [ "python_full_version < '3.11'", "python_full_version >= '3.11'", @@ -154,14 +154,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f1/47/d7145bf2dc04684935d57d67dff9d6d795b2ba2796806bb109864be3a151/cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", size = 488469 }, { url = "https://files.pythonhosted.org/packages/bf/ee/f94057fa6426481d663b88637a9a10e859e492c73d0384514a17d78ee205/cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", size = 172475 }, { url = "https://files.pythonhosted.org/packages/7c/fc/6a8cb64e5f0324877d503c854da15d76c1e50eb722e320b15345c4d0c6de/cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", size = 182009 }, - { url = "https://files.pythonhosted.org/packages/48/08/15bf6b43ae9bd06f6b00ad8a91f5a8fe1069d4c9fab550a866755402724e/cffi-1.17.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b", size = 182457 }, - { url = "https://files.pythonhosted.org/packages/c2/5b/f1523dd545f92f7df468e5f653ffa4df30ac222f3c884e51e139878f1cb5/cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964", size = 425932 }, - { url = "https://files.pythonhosted.org/packages/53/93/7e547ab4105969cc8c93b38a667b82a835dd2cc78f3a7dad6130cfd41e1d/cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9", size = 448585 }, - { url = "https://files.pythonhosted.org/packages/56/c4/a308f2c332006206bb511de219efeff090e9d63529ba0a77aae72e82248b/cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc", size = 456268 }, - { url = "https://files.pythonhosted.org/packages/ca/5b/b63681518265f2f4060d2b60755c1c77ec89e5e045fc3773b72735ddaad5/cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c", size = 436592 }, - { url = "https://files.pythonhosted.org/packages/bb/19/b51af9f4a4faa4a8ac5a0e5d5c2522dcd9703d07fac69da34a36c4d960d3/cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1", size = 446512 }, - { url = "https://files.pythonhosted.org/packages/e2/63/2bed8323890cb613bbecda807688a31ed11a7fe7afe31f8faaae0206a9a3/cffi-1.17.1-cp38-cp38-win32.whl", hash = "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8", size = 171576 }, - { url = "https://files.pythonhosted.org/packages/2f/70/80c33b044ebc79527447fd4fbc5455d514c3bb840dede4455de97da39b4d/cffi-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1", size = 181229 }, { url = "https://files.pythonhosted.org/packages/b9/ea/8bb50596b8ffbc49ddd7a1ad305035daa770202a6b782fc164647c2673ad/cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16", size = 182220 }, { url = "https://files.pythonhosted.org/packages/ae/11/e77c8cd24f58285a82c23af484cf5b124a376b32644e445960d1a4654c3a/cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36", size = 178605 }, { url = "https://files.pythonhosted.org/packages/ed/65/25a8dc32c53bf5b7b6c2686b42ae2ad58743f7ff644844af7cdb29b49361/cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8", size = 424910 }, @@ -242,21 +234,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d8/90/6af4cd042066a4adad58ae25648a12c09c879efa4849c705719ba1b23d8c/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482", size = 144970 }, { url = "https://files.pythonhosted.org/packages/cc/67/e5e7e0cbfefc4ca79025238b43cdf8a2037854195b37d6417f3d0895c4c2/charset_normalizer-3.4.0-cp313-cp313-win32.whl", hash = "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67", size = 94973 }, { url = "https://files.pythonhosted.org/packages/65/97/fc9bbc54ee13d33dc54a7fcf17b26368b18505500fc01e228c27b5222d80/charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b", size = 102308 }, - { url = "https://files.pythonhosted.org/packages/86/f4/ccab93e631e7293cca82f9f7ba39783c967f823a0000df2d8dd743cad74f/charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578", size = 193961 }, - { url = "https://files.pythonhosted.org/packages/94/d4/2b21cb277bac9605026d2d91a4a8872bc82199ed11072d035dc674c27223/charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6", size = 124507 }, - { url = "https://files.pythonhosted.org/packages/9a/e0/a7c1fcdff20d9c667342e0391cfeb33ab01468d7d276b2c7914b371667cc/charset_normalizer-3.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417", size = 119298 }, - { url = "https://files.pythonhosted.org/packages/70/de/1538bb2f84ac9940f7fa39945a5dd1d22b295a89c98240b262fc4b9fcfe0/charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51", size = 139328 }, - { url = "https://files.pythonhosted.org/packages/e9/ca/288bb1a6bc2b74fb3990bdc515012b47c4bc5925c8304fc915d03f94b027/charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41", size = 149368 }, - { url = "https://files.pythonhosted.org/packages/aa/75/58374fdaaf8406f373e508dab3486a31091f760f99f832d3951ee93313e8/charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f", size = 141944 }, - { url = "https://files.pythonhosted.org/packages/32/c8/0bc558f7260db6ffca991ed7166494a7da4fda5983ee0b0bfc8ed2ac6ff9/charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8", size = 143326 }, - { url = "https://files.pythonhosted.org/packages/0e/dd/7f6fec09a1686446cee713f38cf7d5e0669e0bcc8288c8e2924e998cf87d/charset_normalizer-3.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab", size = 146171 }, - { url = "https://files.pythonhosted.org/packages/4c/a8/440f1926d6d8740c34d3ca388fbd718191ec97d3d457a0677eb3aa718fce/charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12", size = 139711 }, - { url = "https://files.pythonhosted.org/packages/e9/7f/4b71e350a3377ddd70b980bea1e2cc0983faf45ba43032b24b2578c14314/charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19", size = 148348 }, - { url = "https://files.pythonhosted.org/packages/1e/70/17b1b9202531a33ed7ef41885f0d2575ae42a1e330c67fddda5d99ad1208/charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea", size = 151290 }, - { url = "https://files.pythonhosted.org/packages/44/30/574b5b5933d77ecb015550aafe1c7d14a8cd41e7e6c4dcea5ae9e8d496c3/charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858", size = 149114 }, - { url = "https://files.pythonhosted.org/packages/0b/11/ca7786f7e13708687443082af20d8341c02e01024275a28bc75032c5ce5d/charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654", size = 143856 }, - { url = "https://files.pythonhosted.org/packages/f9/c2/1727c1438256c71ed32753b23ec2e6fe7b6dff66a598f6566cfe8139305e/charset_normalizer-3.4.0-cp38-cp38-win32.whl", hash = "sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613", size = 94333 }, - { url = "https://files.pythonhosted.org/packages/09/c8/0e17270496a05839f8b500c1166e3261d1226e39b698a735805ec206967b/charset_normalizer-3.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade", size = 101454 }, { url = "https://files.pythonhosted.org/packages/54/2f/28659eee7f5d003e0f5a3b572765bf76d6e0fe6601ab1f1b1dd4cba7e4f1/charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa", size = 196326 }, { url = "https://files.pythonhosted.org/packages/d1/18/92869d5c0057baa973a3ee2af71573be7b084b3c3d428fe6463ce71167f8/charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a", size = 125614 }, { url = "https://files.pythonhosted.org/packages/d6/27/327904c5a54a7796bb9f36810ec4173d2df5d88b401d2b95ef53111d214e/charset_normalizer-3.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0", size = 120450 }, @@ -293,7 +270,6 @@ version = "3.0.5" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, - { name = "typing-extensions", marker = "python_full_version < '3.9'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/cf/71/608e4546208e5a421ef00b484f582e58ce0f17da05459b915c8ba22dfb78/cloup-3.0.5.tar.gz", hash = "sha256:c92b261c7bb7e13004930f3fb4b3edad8de2d1f12994dcddbe05bc21990443c5", size = 225806 } wheels = [ @@ -582,16 +558,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/88/07/2dc76aa51b481eb96a4c3198894f38b480490e834479611a4053fbf08623/MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169", size = 33038 }, { url = "https://files.pythonhosted.org/packages/96/0c/620c1fb3661858c0e37eb3cbffd8c6f732a67cd97296f725789679801b31/MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad", size = 16572 }, { url = "https://files.pythonhosted.org/packages/3f/14/c3554d512d5f9100a95e737502f4a2323a1959f6d0d01e0d0997b35f7b10/MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb", size = 17127 }, - { url = "https://files.pythonhosted.org/packages/f8/ff/2c942a82c35a49df5de3a630ce0a8456ac2969691b230e530ac12314364c/MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a", size = 18192 }, - { url = "https://files.pythonhosted.org/packages/4f/14/6f294b9c4f969d0c801a4615e221c1e084722ea6114ab2114189c5b8cbe0/MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46", size = 14072 }, - { url = "https://files.pythonhosted.org/packages/81/d4/fd74714ed30a1dedd0b82427c02fa4deec64f173831ec716da11c51a50aa/MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532", size = 26928 }, - { url = "https://files.pythonhosted.org/packages/c7/bd/50319665ce81bb10e90d1cf76f9e1aa269ea6f7fa30ab4521f14d122a3df/MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab", size = 26106 }, - { url = "https://files.pythonhosted.org/packages/4c/6f/f2b0f675635b05f6afd5ea03c094557bdb8622fa8e673387444fe8d8e787/MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68", size = 25781 }, - { url = "https://files.pythonhosted.org/packages/51/e0/393467cf899b34a9d3678e78961c2c8cdf49fb902a959ba54ece01273fb1/MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0", size = 30518 }, - { url = "https://files.pythonhosted.org/packages/f6/02/5437e2ad33047290dafced9df741d9efc3e716b75583bbd73a9984f1b6f7/MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4", size = 29669 }, - { url = "https://files.pythonhosted.org/packages/0e/7d/968284145ffd9d726183ed6237c77938c021abacde4e073020f920e060b2/MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3", size = 29933 }, - { url = "https://files.pythonhosted.org/packages/bf/f3/ecb00fc8ab02b7beae8699f34db9357ae49d9f21d4d3de6f305f34fa949e/MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff", size = 16656 }, - { url = "https://files.pythonhosted.org/packages/92/21/357205f03514a49b293e214ac39de01fadd0970a6e05e4bf1ddd0ffd0881/MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029", size = 17206 }, { url = "https://files.pythonhosted.org/packages/0f/31/780bb297db036ba7b7bbede5e1d7f1e14d704ad4beb3ce53fb495d22bc62/MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf", size = 18193 }, { url = "https://files.pythonhosted.org/packages/6c/77/d77701bbef72892affe060cdacb7a2ed7fd68dae3b477a8642f15ad3b132/MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2", size = 14073 }, { url = "https://files.pythonhosted.org/packages/d9/a7/1e558b4f78454c8a3a0199292d96159eb4d091f983bc35ef258314fe7269/MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8", size = 26486 }, @@ -1063,13 +1029,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597 }, { url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527 }, { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446 }, - { url = "https://files.pythonhosted.org/packages/74/d9/323a59d506f12f498c2097488d80d16f4cf965cee1791eab58b56b19f47a/PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a", size = 183218 }, - { url = "https://files.pythonhosted.org/packages/74/cc/20c34d00f04d785f2028737e2e2a8254e1425102e730fee1d6396f832577/PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5", size = 728067 }, - { url = "https://files.pythonhosted.org/packages/20/52/551c69ca1501d21c0de51ddafa8c23a0191ef296ff098e98358f69080577/PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d", size = 757812 }, - { url = "https://files.pythonhosted.org/packages/fd/7f/2c3697bba5d4aa5cc2afe81826d73dfae5f049458e44732c7a0938baa673/PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083", size = 746531 }, - { url = "https://files.pythonhosted.org/packages/8c/ab/6226d3df99900e580091bb44258fde77a8433511a86883bd4681ea19a858/PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706", size = 800820 }, - { url = "https://files.pythonhosted.org/packages/a0/99/a9eb0f3e710c06c5d922026f6736e920d431812ace24aae38228d0d64b04/PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a", size = 145514 }, - { url = "https://files.pythonhosted.org/packages/75/8a/ee831ad5fafa4431099aa4e078d4c8efd43cd5e48fbc774641d233b683a9/PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff", size = 162702 }, { url = "https://files.pythonhosted.org/packages/65/d8/b7a1db13636d7fb7d4ff431593c510c8b8fca920ade06ca8ef20015493c5/PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d", size = 184777 }, { url = "https://files.pythonhosted.org/packages/0a/02/6ec546cd45143fdf9840b2c6be8d875116a64076218b61d68e12548e5839/PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f", size = 172318 }, { url = "https://files.pythonhosted.org/packages/0e/9a/8cc68be846c972bda34f6c2a93abb644fb2476f4dcc924d52175786932c9/PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290", size = 720891 }, From 4b50b4a5dfd36fe4529469bb1d0a13e13edf0740 Mon Sep 17 00:00:00 2001 From: Ruth Netser Date: Thu, 7 Nov 2024 16:53:14 +0200 Subject: [PATCH 14/31] move aws creds and buckets config to pytest_addoption (#34) --- README.md | 12 ----- conftest.py | 22 +++++++++ pyproject.toml | 1 - pytest.ini | 2 - tests/global_config.py | 22 --------- .../model_server/storage/pvc/conftest.py | 48 +++++++++++++------ uv.lock | 2 - 7 files changed, 55 insertions(+), 54 deletions(-) delete mode 100644 tests/global_config.py diff --git a/README.md b/README.md index 28cfbea..cb49ea5 100644 --- a/README.md +++ b/README.md @@ -34,15 +34,3 @@ or by saving the kubeconfig file under `~/.kube/config` ```bash uv run pytest ``` - -### To overwrite a pytest config argument - -```bash -uv run pytest --tc=: -``` - -For example: - -```bash -uv run pytest --tc=ci_s3_bucket_name:my-bucket -``` diff --git a/conftest.py b/conftest.py index f98c931..58c87cd 100644 --- a/conftest.py +++ b/conftest.py @@ -10,6 +10,28 @@ BASIC_LOGGER = logging.getLogger("basic") +def pytest_addoption(parser): + aws_group = parser.getgroup(name="AWS") + buckets_group = parser.getgroup(name="Buckets") + + # AWS config and credentials options + aws_group.addoption( + "--aws-secret-access-key", + default=os.environ.get("AWS_SECRET_ACCESS_KEY"), + help="AWS secret access key", + ) + aws_group.addoption( + "--aws-access-key-id", + default=os.environ.get("AWS_ACCESS_KEY_ID"), + help="AWS access key id", + ) + + # Buckets options + buckets_group.addoption( + "--ci-s3-bucket-name", default=os.environ.get("CI_S3_BUCKET_NAME"), help="Ci S3 bucket name" + ) + + def pytest_sessionstart(session): tests_log_file = session.config.getoption("log_file") or "pytest-tests.log" if os.path.exists(tests_log_file): diff --git a/pyproject.toml b/pyproject.toml index 6ffca8a..14392d0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -42,7 +42,6 @@ dependencies = [ "openshift-python-utilities", "openshift-python-wrapper", "pytest-progress", - "pytest-testconfig", "python-simple-logger", "pyyaml", ] diff --git a/pytest.ini b/pytest.ini index 6027d42..03d7471 100644 --- a/pytest.ini +++ b/pytest.ini @@ -14,6 +14,4 @@ addopts = -p no:logging --basetemp=/tmp/pytest --strict-markers - --tc-file=tests/global_config.py - --tc-format=python --show-progress diff --git a/tests/global_config.py b/tests/global_config.py deleted file mode 100644 index fb97578..0000000 --- a/tests/global_config.py +++ /dev/null @@ -1,22 +0,0 @@ -import os -from typing import Optional - -global config # type: ignore[unused-ignore] - - -# AWS credentials -aws_secret_access_key: Optional[str] = os.environ.get("AWS_SECRET_ACCESS_KEY", "aws_secret_key") -aws_access_key_id: Optional[str] = os.environ.get("AWS_ACCESS_KEY_ID", "aws_access_key") - -# S3 buckets -ci_s3_bucket_name: str = "ci-bucket" - -for _dir in dir(): - val = locals()[_dir] - if type(val) not in [bool, list, dict, str, int]: - continue - - if _dir in ["encoding", "py_file"]: - continue - - config[_dir] = locals()[_dir] # type: ignore[name-defined] # noqa: F821 diff --git a/tests/model_serving/model_server/storage/pvc/conftest.py b/tests/model_serving/model_server/storage/pvc/conftest.py index 2f2fe68..76d1c33 100644 --- a/tests/model_serving/model_server/storage/pvc/conftest.py +++ b/tests/model_serving/model_server/storage/pvc/conftest.py @@ -1,4 +1,3 @@ -import os import shlex from typing import List, Optional, Tuple @@ -15,7 +14,6 @@ from ocp_resources.serving_runtime import ServingRuntime from ocp_resources.storage_class import StorageClass from ocp_utilities.infra import get_pods_by_name_prefix -from pytest_testconfig import config as py_config from tests.model_serving.model_server.storage.constants import NFS_STR from tests.model_serving.model_server.storage.pvc.utils import create_isvc @@ -23,26 +21,32 @@ @pytest.fixture(scope="session") -def aws_access_key() -> Optional[str]: - access_key = py_config.get("aws_access_key_id", os.environ.get("AWS_ACCESS_KEY_ID")) +def aws_access_key_id(pytestconfig) -> Optional[str]: + access_key = pytestconfig.option.aws_access_key_id if not access_key: - raise ValueError("AWS access key is not set") + raise ValueError( + "AWS access key id is not set. " + "Either pass with `--aws-access-key-id` or set `AWS_ACCESS_KEY_ID` environment variable" + ) return access_key @pytest.fixture(scope="session") -def aws_secret_access_key() -> Optional[str]: - secret_access_key = py_config.get("aws_secret_access_key", os.environ.get("AWS_SECRET_ACCESS_KEY")) +def aws_secret_access_key(pytestconfig) -> Optional[str]: + secret_access_key = pytestconfig.option.aws_secret_access_key if not secret_access_key: - raise ValueError("AWS secret key is not set") + raise ValueError( + "AWS secret access key is not set. " + "Either pass with `--aws-secret-access-key` or set `AWS_SECRET_ACCESS_KEY` environment variable" + ) return secret_access_key @pytest.fixture(scope="session") -def valid_aws_config(aws_access_key: str, aws_secret_access_key: str) -> Tuple[str, str]: - return aws_access_key, aws_secret_access_key +def valid_aws_config(aws_access_key_id: str, aws_secret_access_key: str) -> Tuple[str, str]: + return aws_access_key_id, aws_secret_access_key @pytest.fixture(scope="class") @@ -56,9 +60,21 @@ def service_mesh_member(admin_client: DynamicClient, model_namespace: Namespace) yield smm +@pytest.fixture(scope="session") +def ci_s3_bucket_name(pytestconfig) -> str: + bucket_name = pytestconfig.option.ci_s3_bucket_name + if not bucket_name: + raise ValueError( + "CI S3 bucket name is not set. " + "Either pass with `--ci-s3-bucket-name` or set `CI_S3_BUCKET_NAME` environment variable" + ) + + return bucket_name + + @pytest.fixture(scope="class") -def ci_s3_storage_uri(request) -> str: - return f"s3://{py_config['ci_s3_bucket_name']}/{request.param['model-dir']}/" +def ci_s3_storage_uri(request, ci_s3_bucket_name) -> str: + return f"s3://{ci_s3_bucket_name}/{request.param['model-dir']}/" @pytest.fixture(scope="class") @@ -93,7 +109,7 @@ def downloaded_model_data( ci_s3_storage_uri: str, model_pvc: PersistentVolumeClaim, aws_secret_access_key: str, - aws_access_key: str, + aws_access_key_id: str, ) -> str: mount_path: str = "data" model_dir: str = "model-dir" @@ -107,7 +123,7 @@ def downloaded_model_data( "sleep infinity", ], "env": [ - {"name": "AWS_ACCESS_KEY_ID", "value": aws_access_key}, + {"name": "AWS_ACCESS_KEY_ID", "value": aws_access_key_id}, {"name": "AWS_SECRET_ACCESS_KEY", "value": aws_secret_access_key}, ], "volumeMounts": [{"mountPath": mount_path, "name": model_pvc.name, "subPath": model_dir}], @@ -199,7 +215,9 @@ def predictor_pods_scope_function(admin_client: DynamicClient, inference_service @pytest.fixture(scope="class") def predictor_pods_scope_class( - admin_client: DynamicClient, inference_service: InferenceService, isvc_deployment_ready: None + admin_client: DynamicClient, + inference_service: InferenceService, + isvc_deployment_ready: None, ) -> List[Pod]: return get_pods_by_name_prefix( client=admin_client, diff --git a/uv.lock b/uv.lock index 3d00046..182bcdd 100644 --- a/uv.lock +++ b/uv.lock @@ -617,7 +617,6 @@ dependencies = [ { name = "openshift-python-utilities" }, { name = "openshift-python-wrapper" }, { name = "pytest-progress" }, - { name = "pytest-testconfig" }, { name = "python-simple-logger" }, { name = "pyyaml" }, ] @@ -633,7 +632,6 @@ requires-dist = [ { name = "openshift-python-utilities" }, { name = "openshift-python-wrapper" }, { name = "pytest-progress" }, - { name = "pytest-testconfig" }, { name = "python-simple-logger" }, { name = "pyyaml" }, ] From 9212ed08548d069225afa1ca5704aa700daa14ce Mon Sep 17 00:00:00 2001 From: lugi0 Date: Wed, 23 Oct 2024 15:33:11 +0200 Subject: [PATCH 15/31] Add kserve private endpoint tests Signed-off-by: lugi0 --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index c9d5b3b..d881150 100644 --- a/.gitignore +++ b/.gitignore @@ -162,3 +162,7 @@ cython_debug/ # OS generated files # .DS_Store .DS_Store? + +# OS generated files # +.DS_Store +.DS_Store? \ No newline at end of file From 411fb7b988504af5cfd670132f4cf52b669e8279 Mon Sep 17 00:00:00 2001 From: lugi0 Date: Wed, 23 Oct 2024 16:27:54 +0200 Subject: [PATCH 16/31] Fix pre-commit checks, add mypy ini file for vscode extension integration, specify in README that pre-commit shoulb be run and needs NPM installed Signed-off-by: lugi0 --- tests/model_serving/model_server/private_endpoint/infra.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/model_serving/model_server/private_endpoint/infra.py b/tests/model_serving/model_server/private_endpoint/infra.py index 303aea0..04a6062 100644 --- a/tests/model_serving/model_server/private_endpoint/infra.py +++ b/tests/model_serving/model_server/private_endpoint/infra.py @@ -16,6 +16,7 @@ def create_ns( admin_client: DynamicClient = None, teardown: bool = True, delete_timeout: int = TIMEOUT_6MIN, +) -> Generator[Namespace] | Generator[Project]: ) -> Generator[Namespace] | Generator[Project]: if not unprivileged_client: with Namespace( From 7bdf91dc0e8d4023de186d692929172ed56e3ae3 Mon Sep 17 00:00:00 2001 From: lugi0 Date: Mon, 11 Nov 2024 15:42:34 +0100 Subject: [PATCH 17/31] Address PR comments Signed-off-by: lugi0 --- .../model_server/private_endpoint/conftest.py | 116 +++++++----------- .../private_endpoint/constants.py | 6 +- .../model_server/private_endpoint/infra.py | 40 ++---- .../test_kserve_private_endpoint.py | 24 +++- .../model_server/private_endpoint/utils.py | 54 +++++--- .../model_server/storage/pvc/utils.py | 37 ++++-- 6 files changed, 146 insertions(+), 131 deletions(-) diff --git a/tests/model_serving/model_server/private_endpoint/conftest.py b/tests/model_serving/model_server/private_endpoint/conftest.py index b31fa51..99ec0b5 100644 --- a/tests/model_serving/model_server/private_endpoint/conftest.py +++ b/tests/model_serving/model_server/private_endpoint/conftest.py @@ -4,22 +4,21 @@ from ocp_resources.inference_service import InferenceService from ocp_resources.secret import Secret from ocp_resources.namespace import Namespace -from ocp_resources.serving_runtime import ServingRuntime from ocp_resources.pod import Pod from simple_logger.logger import get_logger from ocp_resources.service_mesh_member import ServiceMeshMember +from ocp_resources.serving_runtime import ServingRuntime from kubernetes.dynamic import DynamicClient +from utilities.serving_runtime import ServingRuntimeFromTemplate +from tests.model_serving.model_server.storage.pvc.utils import create_isvc from tests.model_serving.model_server.private_endpoint.utils import create_sidecar_pod, get_flan_pod, b64_encoded_string from tests.model_serving.model_server.private_endpoint.infra import create_ns +from tests.model_serving.model_server.storage.pvc.conftest import aws_access_key_id, aws_secret_access_key from tests.model_serving.model_server.private_endpoint.constants import ( - AWS_REGION, - AWS_BUCKET, - AWS_ENDPOINT, - SR_ANNOTATIONS, - SR_CONTAINERS_KSERVE_CAIKIT, - SR_SUPPORTED_FORMATS_CAIKIT, - SR_VOLUMES, + AWS_REGION_EAST_2, + AWS_BUCKET_WISDOM, + AWS_ENDPOINT_EAST_2, ) @@ -27,12 +26,12 @@ @pytest.fixture(scope="module") -def endpoint_namespace(admin_client: DynamicClient) -> Generator[Namespace]: +def endpoint_namespace(admin_client: DynamicClient) -> Generator[Namespace,None,None]: yield from create_ns(admin_client=admin_client, name="endpoint-namespace") @pytest.fixture(scope="module") -def diff_namespace(admin_client: DynamicClient) -> Generator[Namespace]: +def diff_namespace(admin_client: DynamicClient) -> Generator[Namespace,None,None]: yield from create_ns(admin_client=admin_client, name="diff-namespace") @@ -40,29 +39,28 @@ def diff_namespace(admin_client: DynamicClient) -> Generator[Namespace]: def endpoint_sr( admin_client: DynamicClient, endpoint_namespace: Namespace, -) -> Generator[ServingRuntime]: - with ServingRuntime( +) -> Generator[ServingRuntime,None,None]: + with ServingRuntimeFromTemplate( client=admin_client, name="flan-example-sr", namespace=endpoint_namespace.name, - containers=SR_CONTAINERS_KSERVE_CAIKIT, - multi_model=False, - supported_model_formats=SR_SUPPORTED_FORMATS_CAIKIT, - volumes=SR_VOLUMES, - spec_annotations=SR_ANNOTATIONS, + template_name="caikit-tgis-serving-template", ) as model_runtime: yield model_runtime @pytest.fixture() def endpoint_s3_secret( - admin_client: DynamicClient, endpoint_namespace: Namespace, aws_access_key: str, aws_secret_access_key: str -) -> Generator[Secret]: + admin_client: DynamicClient, + endpoint_namespace: Namespace, + aws_access_key_id: str, + aws_secret_access_key: str, +) -> Generator[Secret,None,None]: data = { - "AWS_ACCESS_KEY_ID": b64_encoded_string(aws_access_key), - "AWS_DEFAULT_REGION": b64_encoded_string(AWS_REGION), - "AWS_S3_BUCKET": b64_encoded_string(AWS_BUCKET), - "AWS_S3_ENDPOINT": b64_encoded_string(AWS_REGION), + "AWS_ACCESS_KEY_ID": b64_encoded_string(aws_access_key_id), + "AWS_DEFAULT_REGION": b64_encoded_string(AWS_REGION_EAST_2), + "AWS_S3_BUCKET": b64_encoded_string(AWS_BUCKET_WISDOM), + "AWS_S3_ENDPOINT": b64_encoded_string(AWS_ENDPOINT_EAST_2), "AWS_SECRET_ACCESS_KEY": b64_encoded_string(aws_secret_access_key), } with Secret( @@ -82,29 +80,17 @@ def endpoint_isvc( endpoint_s3_secret: Secret, storage_config_secret: Secret, endpoint_namespace: Namespace, -) -> Generator[InferenceService]: - predictor = { - "model": { - "modelFormat": { - "name": "caikit", - }, - "name": "kserve-container", - "resources": { - "limits": {"cpu": "2", "memory": "8Gi"}, - "requests": {"cpu": "1", "memory": "4Gi"}, - }, - "runtime": endpoint_sr.name, - "storage": { - "key": "endpoint-s3-secret", - "path": "flan-t5-small/flan-t5-small-caikit", - }, - }, - } - - with InferenceService( - client=admin_client, namespace=endpoint_namespace.name, predictor=predictor, name="test" +) -> Generator[InferenceService,None,None]: + with create_isvc( + client=admin_client, + name="test", + namespace=endpoint_namespace, + deployment_mode="Serverless", + storage_key="endpoint-s3-secret", + storage_path="flan-t5-small/flan-t5-small-caikit", + model_format="caikit", + runtime=endpoint_sr.name, ) as isvc: - isvc.wait_for_condition(condition="Ready", status="True") yield isvc @@ -113,15 +99,15 @@ def storage_config_secret( admin_client: DynamicClient, endpoint_namespace: Namespace, endpoint_s3_secret: Secret, - aws_access_key: str, + aws_access_key_id: str, aws_secret_access_key: str, -) -> Generator[Secret]: +) -> Generator[Secret,None,None]: secret = { - "access_key_id": aws_access_key, - "bucket": AWS_BUCKET, - "default_bucket": AWS_BUCKET, - "endpoint_url": AWS_ENDPOINT, - "region": AWS_REGION, + "access_key_id": aws_access_key_id, + "bucket": AWS_BUCKET_WISDOM, + "default_bucket": AWS_BUCKET_WISDOM, + "endpoint_url": AWS_ENDPOINT_EAST_2, + "region": AWS_REGION_EAST_2, "secret_access_key": aws_secret_access_key, "type": "s3", } @@ -137,7 +123,7 @@ def storage_config_secret( @pytest.fixture() -def service_mesh_member(admin_client: DynamicClient, diff_namespace: Namespace) -> Generator[ServiceMeshMember]: +def service_mesh_member(admin_client: DynamicClient, diff_namespace: Namespace) -> Generator[ServiceMeshMember,None,None]: with ServiceMeshMember( client=admin_client, namespace=diff_namespace.name, @@ -149,51 +135,43 @@ def service_mesh_member(admin_client: DynamicClient, diff_namespace: Namespace) @pytest.fixture() -def endpoint_pod_with_istio_sidecar(admin_client: DynamicClient, endpoint_namespace: Namespace) -> Generator[Pod]: - pod = create_sidecar_pod( +def endpoint_pod_with_istio_sidecar(admin_client: DynamicClient, endpoint_namespace: Namespace) -> Pod: + return create_sidecar_pod( admin_client=admin_client, namespace=endpoint_namespace.name, istio=True, pod_name="test-with-istio", ) - yield pod - pod.clean_up() @pytest.fixture() -def endpoint_pod_without_istio_sidecar(admin_client: DynamicClient, endpoint_namespace: Namespace) -> Generator[Pod]: - pod = create_sidecar_pod( +def endpoint_pod_without_istio_sidecar(admin_client: DynamicClient, endpoint_namespace: Namespace) -> Pod: + return create_sidecar_pod( admin_client=admin_client, namespace=endpoint_namespace.name, istio=False, pod_name="test", ) - yield pod - pod.clean_up() @pytest.fixture() -def diff_pod_with_istio_sidecar(admin_client: DynamicClient, diff_namespace: Namespace) -> Generator[Pod]: - pod = create_sidecar_pod( +def diff_pod_with_istio_sidecar(admin_client: DynamicClient, diff_namespace: Namespace) -> Pod: + return create_sidecar_pod( admin_client=admin_client, namespace=diff_namespace.name, istio=True, pod_name="test-with-istio", ) - yield pod - pod.clean_up() @pytest.fixture() -def diff_pod_without_istio_sidecar(admin_client: DynamicClient, diff_namespace: Namespace) -> Generator[Pod]: - pod = create_sidecar_pod( +def diff_pod_without_istio_sidecar(admin_client: DynamicClient, diff_namespace: Namespace) -> Pod: + return create_sidecar_pod( admin_client=admin_client, namespace=diff_namespace.name, istio=False, pod_name="test", ) - yield pod - pod.clean_up() @pytest.fixture() diff --git a/tests/model_serving/model_server/private_endpoint/constants.py b/tests/model_serving/model_server/private_endpoint/constants.py index 166bcd6..f61eed1 100644 --- a/tests/model_serving/model_server/private_endpoint/constants.py +++ b/tests/model_serving/model_server/private_endpoint/constants.py @@ -1,8 +1,8 @@ from typing import Dict, List, Any -AWS_REGION: str = "us-east-2" -AWS_BUCKET: str = "ods-ci-wisdom" -AWS_ENDPOINT: str = "https://s3.us-east-2.amazonaws.com/" +AWS_REGION_EAST_2: str = "us-east-2" +AWS_BUCKET_WISDOM: str = "ods-ci-wisdom" +AWS_ENDPOINT_EAST_2: str = "https://s3.us-east-2.amazonaws.com/" SR_CONTAINERS_KSERVE_CAIKIT: List[Dict[Any, Any]] = [ { diff --git a/tests/model_serving/model_server/private_endpoint/infra.py b/tests/model_serving/model_server/private_endpoint/infra.py index 04a6062..0b0f022 100644 --- a/tests/model_serving/model_server/private_endpoint/infra.py +++ b/tests/model_serving/model_server/private_endpoint/infra.py @@ -3,39 +3,21 @@ from kubernetes.dynamic import DynamicClient from ocp_resources.namespace import Namespace from ocp_resources.project_project_openshift_io import Project -from ocp_resources.project_request import ProjectRequest - -TIMEOUT_2MIN = 2 * 10 -TIMEOUT_6MIN = 6 * 10 def create_ns( name: str, - unprivileged_client: DynamicClient = None, labels: Optional[Dict[str, str]] = None, admin_client: DynamicClient = None, teardown: bool = True, - delete_timeout: int = TIMEOUT_6MIN, -) -> Generator[Namespace] | Generator[Project]: -) -> Generator[Namespace] | Generator[Project]: - if not unprivileged_client: - with Namespace( - client=admin_client, - name=name, - label=labels, - teardown=teardown, - delete_timeout=delete_timeout, - ) as ns: - ns.wait_for_status(status=Namespace.Status.ACTIVE, timeout=TIMEOUT_2MIN) - yield ns - else: - with ProjectRequest(name=name, client=unprivileged_client, teardown=teardown): - project = Project( - name=name, - client=unprivileged_client, - label=labels, - teardown=teardown, - delete_timeout=delete_timeout, - ) - project.wait_for_status(project.Status.ACTIVE, timeout=TIMEOUT_2MIN) - yield project + delete_timeout: int = 6 * 10, +) -> Generator[Namespace,None,None]: + with Namespace( + client=admin_client, + name=name, + label=labels, + teardown=teardown, + delete_timeout=delete_timeout, + ) as ns: + ns.wait_for_status(status=Namespace.Status.ACTIVE, timeout=2 * 10) + yield ns diff --git a/tests/model_serving/model_server/private_endpoint/test_kserve_private_endpoint.py b/tests/model_serving/model_server/private_endpoint/test_kserve_private_endpoint.py index 0b1ed42..3920e29 100644 --- a/tests/model_serving/model_server/private_endpoint/test_kserve_private_endpoint.py +++ b/tests/model_serving/model_server/private_endpoint/test_kserve_private_endpoint.py @@ -12,16 +12,20 @@ class TestKserveInternalEndpoint: - def test_deploy_model( + def test_deploy_model_state_loaded( self: Self, endpoint_namespace: Namespace, endpoint_isvc: InferenceService, running_flan_pod: Pod ) -> None: assert endpoint_isvc.instance.status.modelStatus.states.activeModelState == "Loaded" + + def test_deploy_model_url( + self: Self, endpoint_namespace: Namespace, endpoint_isvc: InferenceService, running_flan_pod: Pod + ) -> None: assert ( endpoint_isvc.instance.status.address.url == f"https://{endpoint_isvc.name}.{endpoint_namespace.name}.svc.cluster.local" ) - def test_curl_with_istio( + def test_curl_with_istio_same_ns( self: Self, endpoint_isvc: InferenceService, endpoint_pod_with_istio_sidecar: Pod, @@ -37,6 +41,13 @@ def test_curl_with_istio( ) assert curl_stdout == "OK" + def test_curl_with_istio_diff_ns( + self: Self, + endpoint_isvc: InferenceService, + endpoint_pod_with_istio_sidecar: Pod, + diff_pod_with_istio_sidecar: Pod, + service_mesh_member: ServiceMeshMember, + ) -> None: LOGGER.info("Testing curl from a different namespace with a pod part of the service mesh") curl_stdout = curl_from_pod( @@ -47,7 +58,7 @@ def test_curl_with_istio( ) assert curl_stdout == "OK" - def test_curl_outside_istio( + def test_curl_outside_istio_same_ns( self: Self, endpoint_isvc: InferenceService, endpoint_pod_without_istio_sidecar: Pod, @@ -64,6 +75,13 @@ def test_curl_outside_istio( ) assert curl_stdout == "OK" + def test_curl_outside_istio_diff_ns( + self: Self, + endpoint_isvc: InferenceService, + endpoint_pod_without_istio_sidecar: Pod, + diff_pod_without_istio_sidecar: Pod, + service_mesh_member: ServiceMeshMember, + ) -> None: LOGGER.info("Testing curl from a different namespace with a pod not part of the service mesh") curl_stdout = curl_from_pod( diff --git a/tests/model_serving/model_server/private_endpoint/utils.py b/tests/model_serving/model_server/private_endpoint/utils.py index c7e1c79..3f1d39f 100644 --- a/tests/model_serving/model_server/private_endpoint/utils.py +++ b/tests/model_serving/model_server/private_endpoint/utils.py @@ -1,8 +1,11 @@ import shlex import base64 +from typing import Optional, Generator +from urllib.parse import urlparse from ocp_resources.pod import Pod from kubernetes.dynamic.client import DynamicClient +from kubernetes.dynamic.exceptions import ResourceNotFoundError from ocp_resources.inference_service import InferenceService from pyhelper_utils.shell import run_command from simple_logger.logger import get_logger @@ -11,15 +14,33 @@ LOGGER = get_logger(name=__name__) -class FlanPodNotFoundError(Exception): - pass - - class ProtocolNotSupported(Exception): def __init__(self, protocol: str): self.protocol = protocol - self.message = f"Protocol {protocol} is not supported" - super().__init__(self.message) + def __str__(self) -> str: + return f"Protocol {self.protocol} is not supported" + +class MissingStorageArgument(Exception): + def __init__( + self, + storageUri: Optional[str], + storage_key: Optional[str], + storage_path: Optional[str], + ): + self.storageUri=storageUri + self.storage_key=storage_key + self.storage_path=storage_path + + def __str__(self) -> str: + msg = f""" + You've passed the following parameters: + "storageUri": {self.storageUri} + "storage_key": {self.storage_key} + "storage_path: {self.storage_path} + In order to create a valid ISVC you need to specify either a storageUri value + or both a storage key and a storage path. + """ + return msg def get_flan_pod(client: DynamicClient, namespace: str, name_prefix: str) -> Pod: @@ -27,7 +48,7 @@ def get_flan_pod(client: DynamicClient, namespace: str, name_prefix: str) -> Pod if name_prefix + "-predictor" in pod.name: return pod - raise FlanPodNotFoundError(f"No flan predictor pod found in namespace {namespace}") + raise ResourceNotFoundError(f"No flan predictor pod found in namespace {namespace}") def curl_from_pod( @@ -37,8 +58,8 @@ def curl_from_pod( protocol: str = "http", ) -> str: if protocol == "http": - tmp = isvc.instance.status.address.url - host = "http://" + tmp.split("://")[1] + parsed = urlparse(isvc.instance.status.address.url) + host = parsed._replace(scheme="http").geturl() elif protocol == "https": host = isvc.instance.status.address.url @@ -53,7 +74,7 @@ def create_sidecar_pod( namespace: str, istio: bool, pod_name: str, -) -> Pod: +) -> Generator[Pod,None,None]: cmd = f"oc run {pod_name} -n {namespace} --image=registry.access.redhat.com/rhel7/rhel-tools" if istio: cmd = f'{cmd} --annotations=sidecar.istio.io/inject="true"' @@ -62,13 +83,16 @@ def create_sidecar_pod( _, _, err = run_command(command=shlex.split(cmd), check=False) if err: - # pytest.fail(f"Failed on {err}") LOGGER.info(msg=err) - pod = Pod(name=pod_name, namespace=namespace, client=admin_client) - pod.wait_for_status(status="Running") - pod.wait_for_condition(condition="Ready", status="True") - return pod + with Pod( + name=pod_name, + namespace=namespace, + client=admin_client, + ) as p: + p.wait_for_status(status="Running") + p.wait_for_condition(condition="Ready", status="True") + yield p def b64_encoded_string(string_to_encode: str) -> str: diff --git a/tests/model_serving/model_server/storage/pvc/utils.py b/tests/model_serving/model_server/storage/pvc/utils.py index 7feaea0..6ff2eaf 100644 --- a/tests/model_serving/model_server/storage/pvc/utils.py +++ b/tests/model_serving/model_server/storage/pvc/utils.py @@ -1,7 +1,9 @@ from contextlib import contextmanager +from typing import Optional, Generator, Any from kubernetes.dynamic import DynamicClient from ocp_resources.inference_service import InferenceService +from tests.model_serving.model_server.private_endpoint.utils import MissingStorageArgument @contextmanager @@ -10,12 +12,32 @@ def create_isvc( name: str, namespace: str, deployment_mode: str, - storage_uri: str, model_format: str, runtime: str, + storage_uri: Optional[str] = None, + storage_key: Optional[str] = None, + storage_path: Optional[str] = None, min_replicas: int = 1, wait: bool = True, -) -> InferenceService: +) -> Generator[InferenceService,Any,Any]: + predictor_storage={ + "minReplicas": min_replicas, + "model": { + "modelFormat": {"name": model_format}, + "version": "1", + "runtime": runtime, + }, + } + if storage_uri: + predictor_storage["model"]["storageUri"] = storage_uri + elif storage_key and storage_path: + predictor_storage["storage"] = { + "key": storage_key, + "path": storage_path, + } + else: + raise MissingStorageArgument(storage_uri, storage_key, storage_path) + with InferenceService( client=client, name=name, @@ -26,15 +48,7 @@ def create_isvc( "sidecar.istio.io/rewriteAppHTTPProbers": "true", "serving.kserve.io/deploymentMode": deployment_mode, }, - predictor={ - "minReplicas": min_replicas, - "model": { - "modelFormat": {"name": model_format}, - "version": "1", - "runtime": runtime, - "storageUri": storage_uri, - }, - }, + predictor=predictor_storage, ) as inference_service: if wait: inference_service.wait_for_condition( @@ -42,5 +56,4 @@ def create_isvc( status=inference_service.Condition.Status.TRUE, timeout=10 * 60, ) - yield inference_service From 6326c458b34f3bdf81e937f68dbfc4a4ef467485 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 11 Nov 2024 14:45:49 +0000 Subject: [PATCH 18/31] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .gitignore | 2 +- .../model_server/private_endpoint/conftest.py | 19 +++++++------- .../model_server/private_endpoint/infra.py | 3 +-- .../test_kserve_private_endpoint.py | 2 +- .../model_server/private_endpoint/utils.py | 24 +++++++++-------- .../model_server/storage/pvc/utils.py | 26 +++++++++---------- 6 files changed, 39 insertions(+), 37 deletions(-) diff --git a/.gitignore b/.gitignore index d881150..b6f77c8 100644 --- a/.gitignore +++ b/.gitignore @@ -165,4 +165,4 @@ cython_debug/ # OS generated files # .DS_Store -.DS_Store? \ No newline at end of file +.DS_Store? diff --git a/tests/model_serving/model_server/private_endpoint/conftest.py b/tests/model_serving/model_server/private_endpoint/conftest.py index 99ec0b5..ac8bacc 100644 --- a/tests/model_serving/model_server/private_endpoint/conftest.py +++ b/tests/model_serving/model_server/private_endpoint/conftest.py @@ -14,7 +14,6 @@ from tests.model_serving.model_server.storage.pvc.utils import create_isvc from tests.model_serving.model_server.private_endpoint.utils import create_sidecar_pod, get_flan_pod, b64_encoded_string from tests.model_serving.model_server.private_endpoint.infra import create_ns -from tests.model_serving.model_server.storage.pvc.conftest import aws_access_key_id, aws_secret_access_key from tests.model_serving.model_server.private_endpoint.constants import ( AWS_REGION_EAST_2, AWS_BUCKET_WISDOM, @@ -26,12 +25,12 @@ @pytest.fixture(scope="module") -def endpoint_namespace(admin_client: DynamicClient) -> Generator[Namespace,None,None]: +def endpoint_namespace(admin_client: DynamicClient) -> Generator[Namespace, None, None]: yield from create_ns(admin_client=admin_client, name="endpoint-namespace") @pytest.fixture(scope="module") -def diff_namespace(admin_client: DynamicClient) -> Generator[Namespace,None,None]: +def diff_namespace(admin_client: DynamicClient) -> Generator[Namespace, None, None]: yield from create_ns(admin_client=admin_client, name="diff-namespace") @@ -39,7 +38,7 @@ def diff_namespace(admin_client: DynamicClient) -> Generator[Namespace,None,None def endpoint_sr( admin_client: DynamicClient, endpoint_namespace: Namespace, -) -> Generator[ServingRuntime,None,None]: +) -> Generator[ServingRuntime, None, None]: with ServingRuntimeFromTemplate( client=admin_client, name="flan-example-sr", @@ -53,9 +52,9 @@ def endpoint_sr( def endpoint_s3_secret( admin_client: DynamicClient, endpoint_namespace: Namespace, - aws_access_key_id: str, + aws_access_key_id: str, aws_secret_access_key: str, -) -> Generator[Secret,None,None]: +) -> Generator[Secret, None, None]: data = { "AWS_ACCESS_KEY_ID": b64_encoded_string(aws_access_key_id), "AWS_DEFAULT_REGION": b64_encoded_string(AWS_REGION_EAST_2), @@ -80,7 +79,7 @@ def endpoint_isvc( endpoint_s3_secret: Secret, storage_config_secret: Secret, endpoint_namespace: Namespace, -) -> Generator[InferenceService,None,None]: +) -> Generator[InferenceService, None, None]: with create_isvc( client=admin_client, name="test", @@ -101,7 +100,7 @@ def storage_config_secret( endpoint_s3_secret: Secret, aws_access_key_id: str, aws_secret_access_key: str, -) -> Generator[Secret,None,None]: +) -> Generator[Secret, None, None]: secret = { "access_key_id": aws_access_key_id, "bucket": AWS_BUCKET_WISDOM, @@ -123,7 +122,9 @@ def storage_config_secret( @pytest.fixture() -def service_mesh_member(admin_client: DynamicClient, diff_namespace: Namespace) -> Generator[ServiceMeshMember,None,None]: +def service_mesh_member( + admin_client: DynamicClient, diff_namespace: Namespace +) -> Generator[ServiceMeshMember, None, None]: with ServiceMeshMember( client=admin_client, namespace=diff_namespace.name, diff --git a/tests/model_serving/model_server/private_endpoint/infra.py b/tests/model_serving/model_server/private_endpoint/infra.py index 0b0f022..c3aa19e 100644 --- a/tests/model_serving/model_server/private_endpoint/infra.py +++ b/tests/model_serving/model_server/private_endpoint/infra.py @@ -2,7 +2,6 @@ from kubernetes.dynamic import DynamicClient from ocp_resources.namespace import Namespace -from ocp_resources.project_project_openshift_io import Project def create_ns( @@ -11,7 +10,7 @@ def create_ns( admin_client: DynamicClient = None, teardown: bool = True, delete_timeout: int = 6 * 10, -) -> Generator[Namespace,None,None]: +) -> Generator[Namespace, None, None]: with Namespace( client=admin_client, name=name, diff --git a/tests/model_serving/model_server/private_endpoint/test_kserve_private_endpoint.py b/tests/model_serving/model_server/private_endpoint/test_kserve_private_endpoint.py index 3920e29..3093dc1 100644 --- a/tests/model_serving/model_server/private_endpoint/test_kserve_private_endpoint.py +++ b/tests/model_serving/model_server/private_endpoint/test_kserve_private_endpoint.py @@ -16,7 +16,7 @@ def test_deploy_model_state_loaded( self: Self, endpoint_namespace: Namespace, endpoint_isvc: InferenceService, running_flan_pod: Pod ) -> None: assert endpoint_isvc.instance.status.modelStatus.states.activeModelState == "Loaded" - + def test_deploy_model_url( self: Self, endpoint_namespace: Namespace, endpoint_isvc: InferenceService, running_flan_pod: Pod ) -> None: diff --git a/tests/model_serving/model_server/private_endpoint/utils.py b/tests/model_serving/model_server/private_endpoint/utils.py index 3f1d39f..741da49 100644 --- a/tests/model_serving/model_server/private_endpoint/utils.py +++ b/tests/model_serving/model_server/private_endpoint/utils.py @@ -17,19 +17,21 @@ class ProtocolNotSupported(Exception): def __init__(self, protocol: str): self.protocol = protocol + def __str__(self) -> str: return f"Protocol {self.protocol} is not supported" - + + class MissingStorageArgument(Exception): def __init__( - self, - storageUri: Optional[str], - storage_key: Optional[str], - storage_path: Optional[str], - ): - self.storageUri=storageUri - self.storage_key=storage_key - self.storage_path=storage_path + self, + storageUri: Optional[str], + storage_key: Optional[str], + storage_path: Optional[str], + ): + self.storageUri = storageUri + self.storage_key = storage_key + self.storage_path = storage_path def __str__(self) -> str: msg = f""" @@ -38,7 +40,7 @@ def __str__(self) -> str: "storage_key": {self.storage_key} "storage_path: {self.storage_path} In order to create a valid ISVC you need to specify either a storageUri value - or both a storage key and a storage path. + or both a storage key and a storage path. """ return msg @@ -74,7 +76,7 @@ def create_sidecar_pod( namespace: str, istio: bool, pod_name: str, -) -> Generator[Pod,None,None]: +) -> Generator[Pod, None, None]: cmd = f"oc run {pod_name} -n {namespace} --image=registry.access.redhat.com/rhel7/rhel-tools" if istio: cmd = f'{cmd} --annotations=sidecar.istio.io/inject="true"' diff --git a/tests/model_serving/model_server/storage/pvc/utils.py b/tests/model_serving/model_server/storage/pvc/utils.py index 6ff2eaf..7dfeeae 100644 --- a/tests/model_serving/model_server/storage/pvc/utils.py +++ b/tests/model_serving/model_server/storage/pvc/utils.py @@ -19,22 +19,22 @@ def create_isvc( storage_path: Optional[str] = None, min_replicas: int = 1, wait: bool = True, -) -> Generator[InferenceService,Any,Any]: - predictor_storage={ - "minReplicas": min_replicas, - "model": { - "modelFormat": {"name": model_format}, - "version": "1", - "runtime": runtime, - }, - } +) -> Generator[InferenceService, Any, Any]: + predictor_storage = { + "minReplicas": min_replicas, + "model": { + "modelFormat": {"name": model_format}, + "version": "1", + "runtime": runtime, + }, + } if storage_uri: predictor_storage["model"]["storageUri"] = storage_uri elif storage_key and storage_path: - predictor_storage["storage"] = { - "key": storage_key, - "path": storage_path, - } + predictor_storage["storage"] = { + "key": storage_key, + "path": storage_path, + } else: raise MissingStorageArgument(storage_uri, storage_key, storage_path) From 9f7412283fbfdc84a730c6b694ae12ca22a14868 Mon Sep 17 00:00:00 2001 From: lugi0 Date: Mon, 11 Nov 2024 18:28:36 +0100 Subject: [PATCH 19/31] fix failures, pre-commit Signed-off-by: lugi0 --- conftest.py | 20 +++++++++++ .../model_server/private_endpoint/conftest.py | 35 ++++++++++++++----- .../private_endpoint/constants.py | 31 ---------------- .../test_kserve_private_endpoint.py | 4 --- .../model_server/private_endpoint/utils.py | 32 +++++++++++------ .../model_server/storage/pvc/utils.py | 17 ++++++--- 6 files changed, 80 insertions(+), 59 deletions(-) diff --git a/conftest.py b/conftest.py index 58c87cd..5eb847d 100644 --- a/conftest.py +++ b/conftest.py @@ -2,6 +2,8 @@ import os import pathlib import shutil +import pytest +from typing import Optional from utilities.logger import separator, setup_logging @@ -31,6 +33,12 @@ def pytest_addoption(parser): "--ci-s3-bucket-name", default=os.environ.get("CI_S3_BUCKET_NAME"), help="Ci S3 bucket name" ) + buckets_group.addoption( + "--ci-s3-bucket-name-wisdom", + default=os.environ.get("CI_S3_BUCKET_NAME_WISDOM"), + help="Ci S3 bucket name - wisdom", + ) + def pytest_sessionstart(session): tests_log_file = session.config.getoption("log_file") or "pytest-tests.log" @@ -83,3 +91,15 @@ def pytest_sessionfinish(session, exitstatus): reporter = session.config.pluginmanager.get_plugin("terminalreporter") reporter.summary_stats() + + +@pytest.fixture(scope="session") +def s3_bucket_name_wisdom(pytestconfig: pytest.Config) -> Optional[str]: + wisdom_bucket = pytestconfig.option.ci_s3_bucket_name_wisdom + if not wisdom_bucket: + raise ValueError( + "Bucket name for wisdom bucket is not defined." + "Either pass with `--ci-s3-bucket-name-wisdom` or set `CI_S3_BUCKET_NAME_WISDOM` environment variable" + ) + + return wisdom_bucket diff --git a/tests/model_serving/model_server/private_endpoint/conftest.py b/tests/model_serving/model_server/private_endpoint/conftest.py index ac8bacc..404d006 100644 --- a/tests/model_serving/model_server/private_endpoint/conftest.py +++ b/tests/model_serving/model_server/private_endpoint/conftest.py @@ -16,7 +16,6 @@ from tests.model_serving.model_server.private_endpoint.infra import create_ns from tests.model_serving.model_server.private_endpoint.constants import ( AWS_REGION_EAST_2, - AWS_BUCKET_WISDOM, AWS_ENDPOINT_EAST_2, ) @@ -25,11 +24,13 @@ @pytest.fixture(scope="module") +def endpoint_namespace(admin_client: DynamicClient) -> Generator[Namespace, None, None]: def endpoint_namespace(admin_client: DynamicClient) -> Generator[Namespace, None, None]: yield from create_ns(admin_client=admin_client, name="endpoint-namespace") @pytest.fixture(scope="module") +def diff_namespace(admin_client: DynamicClient) -> Generator[Namespace, None, None]: def diff_namespace(admin_client: DynamicClient) -> Generator[Namespace, None, None]: yield from create_ns(admin_client=admin_client, name="diff-namespace") @@ -38,6 +39,7 @@ def diff_namespace(admin_client: DynamicClient) -> Generator[Namespace, None, No def endpoint_sr( admin_client: DynamicClient, endpoint_namespace: Namespace, +) -> Generator[ServingRuntime, None, None]: ) -> Generator[ServingRuntime, None, None]: with ServingRuntimeFromTemplate( client=admin_client, @@ -53,12 +55,14 @@ def endpoint_s3_secret( admin_client: DynamicClient, endpoint_namespace: Namespace, aws_access_key_id: str, + aws_access_key_id: str, aws_secret_access_key: str, + s3_bucket_name_wisdom: str, ) -> Generator[Secret, None, None]: data = { "AWS_ACCESS_KEY_ID": b64_encoded_string(aws_access_key_id), "AWS_DEFAULT_REGION": b64_encoded_string(AWS_REGION_EAST_2), - "AWS_S3_BUCKET": b64_encoded_string(AWS_BUCKET_WISDOM), + "AWS_S3_BUCKET": b64_encoded_string(s3_bucket_name_wisdom), "AWS_S3_ENDPOINT": b64_encoded_string(AWS_ENDPOINT_EAST_2), "AWS_SECRET_ACCESS_KEY": b64_encoded_string(aws_secret_access_key), } @@ -79,11 +83,12 @@ def endpoint_isvc( endpoint_s3_secret: Secret, storage_config_secret: Secret, endpoint_namespace: Namespace, +) -> Generator[InferenceService, None, None]: ) -> Generator[InferenceService, None, None]: with create_isvc( client=admin_client, name="test", - namespace=endpoint_namespace, + namespace=endpoint_namespace.name, deployment_mode="Serverless", storage_key="endpoint-s3-secret", storage_path="flan-t5-small/flan-t5-small-caikit", @@ -100,11 +105,12 @@ def storage_config_secret( endpoint_s3_secret: Secret, aws_access_key_id: str, aws_secret_access_key: str, + s3_bucket_name_wisdom: str, ) -> Generator[Secret, None, None]: secret = { "access_key_id": aws_access_key_id, - "bucket": AWS_BUCKET_WISDOM, - "default_bucket": AWS_BUCKET_WISDOM, + "bucket": s3_bucket_name_wisdom, + "default_bucket": s3_bucket_name_wisdom, "endpoint_url": AWS_ENDPOINT_EAST_2, "region": AWS_REGION_EAST_2, "secret_access_key": aws_secret_access_key, @@ -122,6 +128,9 @@ def storage_config_secret( @pytest.fixture() +def service_mesh_member( + admin_client: DynamicClient, diff_namespace: Namespace +) -> Generator[ServiceMeshMember, None, None]: def service_mesh_member( admin_client: DynamicClient, diff_namespace: Namespace ) -> Generator[ServiceMeshMember, None, None]: @@ -137,42 +146,50 @@ def service_mesh_member( @pytest.fixture() def endpoint_pod_with_istio_sidecar(admin_client: DynamicClient, endpoint_namespace: Namespace) -> Pod: - return create_sidecar_pod( + pod = create_sidecar_pod( admin_client=admin_client, namespace=endpoint_namespace.name, istio=True, pod_name="test-with-istio", ) + yield pod + pod.clean_up() @pytest.fixture() def endpoint_pod_without_istio_sidecar(admin_client: DynamicClient, endpoint_namespace: Namespace) -> Pod: - return create_sidecar_pod( + pod = create_sidecar_pod( admin_client=admin_client, namespace=endpoint_namespace.name, istio=False, pod_name="test", ) + yield pod + pod.clean_up() @pytest.fixture() def diff_pod_with_istio_sidecar(admin_client: DynamicClient, diff_namespace: Namespace) -> Pod: - return create_sidecar_pod( + pod = create_sidecar_pod( admin_client=admin_client, namespace=diff_namespace.name, istio=True, pod_name="test-with-istio", ) + yield pod + pod.clean_up() @pytest.fixture() def diff_pod_without_istio_sidecar(admin_client: DynamicClient, diff_namespace: Namespace) -> Pod: - return create_sidecar_pod( + pod = create_sidecar_pod( admin_client=admin_client, namespace=diff_namespace.name, istio=False, pod_name="test", ) + yield pod + pod.clean_up() @pytest.fixture() diff --git a/tests/model_serving/model_server/private_endpoint/constants.py b/tests/model_serving/model_server/private_endpoint/constants.py index f61eed1..150b9f2 100644 --- a/tests/model_serving/model_server/private_endpoint/constants.py +++ b/tests/model_serving/model_server/private_endpoint/constants.py @@ -1,33 +1,2 @@ -from typing import Dict, List, Any - AWS_REGION_EAST_2: str = "us-east-2" -AWS_BUCKET_WISDOM: str = "ods-ci-wisdom" AWS_ENDPOINT_EAST_2: str = "https://s3.us-east-2.amazonaws.com/" - -SR_CONTAINERS_KSERVE_CAIKIT: List[Dict[Any, Any]] = [ - { - "args": ["--model-name=/mnt/models/artifacts/"], - "command": ["text-generation-launcher"], - "env": [{"name": "HF_HOME", "value": "/tmp/hf_home"}], - "image": "quay.io/modh/text-generation-inference@sha256:294f07b2a94a223a18e559d497a79cac53bf7893f36cfc6c995475b6e431bcfe", - "name": "kserve-container", - "volumeMounts": [{"mountPath": "/dev/shm", "name": "shm"}], - }, - { - "env": [ - {"name": "RUNTIME_LOCAL_MODELS_DIR", "value": "/mnt/models"}, - {"name": "HF_HOME", "value": "/tmp/hf_home"}, - {"name": "RUNTIME_GRPC_ENABLED", "value": "false"}, - {"name": "RUNTIME_HTTP_ENABLED", "value": "true"}, - ], - "image": "quay.io/modh/caikit-tgis-serving@sha256:4e907ce35a3767f5be2f3175a1854e8d4456c43b78cf3df4305bceabcbf0d6e2", - "name": "transformer-container", - "ports": [{"containerPort": 8080, "protocol": "TCP"}], - "volumeMounts": [{"mountPath": "/dev/shm", "name": "shm"}], - }, -] -SR_SUPPORTED_FORMATS_CAIKIT: List[Dict[Any, Any]] = [ - {"autoSelect": True, "name": "caikit"}, -] -SR_VOLUMES: List[Dict[Any, Any]] = [{"emptyDir": {"medium": "Memory", "sizeLimit": "2Gi"}, "name": "shm"}] -SR_ANNOTATIONS: Dict[str, str] = {"prometheus.io/path": "/metrics", "prometheus.io/port": "3000"} diff --git a/tests/model_serving/model_server/private_endpoint/test_kserve_private_endpoint.py b/tests/model_serving/model_server/private_endpoint/test_kserve_private_endpoint.py index 3093dc1..c1483a9 100644 --- a/tests/model_serving/model_server/private_endpoint/test_kserve_private_endpoint.py +++ b/tests/model_serving/model_server/private_endpoint/test_kserve_private_endpoint.py @@ -29,7 +29,6 @@ def test_curl_with_istio_same_ns( self: Self, endpoint_isvc: InferenceService, endpoint_pod_with_istio_sidecar: Pod, - diff_pod_with_istio_sidecar: Pod, service_mesh_member: ServiceMeshMember, ) -> None: LOGGER.info("Testing curl from the same namespace with a pod part of the service mesh") @@ -44,7 +43,6 @@ def test_curl_with_istio_same_ns( def test_curl_with_istio_diff_ns( self: Self, endpoint_isvc: InferenceService, - endpoint_pod_with_istio_sidecar: Pod, diff_pod_with_istio_sidecar: Pod, service_mesh_member: ServiceMeshMember, ) -> None: @@ -62,7 +60,6 @@ def test_curl_outside_istio_same_ns( self: Self, endpoint_isvc: InferenceService, endpoint_pod_without_istio_sidecar: Pod, - diff_pod_without_istio_sidecar: Pod, service_mesh_member: ServiceMeshMember, ) -> None: LOGGER.info("Testing curl from the same namespace with a pod not part of the service mesh") @@ -78,7 +75,6 @@ def test_curl_outside_istio_same_ns( def test_curl_outside_istio_diff_ns( self: Self, endpoint_isvc: InferenceService, - endpoint_pod_without_istio_sidecar: Pod, diff_pod_without_istio_sidecar: Pod, service_mesh_member: ServiceMeshMember, ) -> None: diff --git a/tests/model_serving/model_server/private_endpoint/utils.py b/tests/model_serving/model_server/private_endpoint/utils.py index 741da49..3670834 100644 --- a/tests/model_serving/model_server/private_endpoint/utils.py +++ b/tests/model_serving/model_server/private_endpoint/utils.py @@ -1,6 +1,6 @@ import shlex import base64 -from typing import Optional, Generator +from typing import Optional from urllib.parse import urlparse from ocp_resources.pod import Pod @@ -18,16 +18,27 @@ class ProtocolNotSupported(Exception): def __init__(self, protocol: str): self.protocol = protocol + def __str__(self) -> str: return f"Protocol {self.protocol} is not supported" + + class MissingStorageArgument(Exception): def __init__( self, storageUri: Optional[str], storage_key: Optional[str], storage_path: Optional[str], + ): + self.storageUri = storageUri + self.storage_key = storage_key + self.storage_path = storage_path + self, + storageUri: Optional[str], + storage_key: Optional[str], + storage_path: Optional[str], ): self.storageUri = storageUri self.storage_key = storage_key @@ -41,6 +52,7 @@ def __str__(self) -> str: "storage_path: {self.storage_path} In order to create a valid ISVC you need to specify either a storageUri value or both a storage key and a storage path. + or both a storage key and a storage path. """ return msg @@ -76,7 +88,7 @@ def create_sidecar_pod( namespace: str, istio: bool, pod_name: str, -) -> Generator[Pod, None, None]: +) -> Pod: cmd = f"oc run {pod_name} -n {namespace} --image=registry.access.redhat.com/rhel7/rhel-tools" if istio: cmd = f'{cmd} --annotations=sidecar.istio.io/inject="true"' @@ -87,14 +99,14 @@ def create_sidecar_pod( if err: LOGGER.info(msg=err) - with Pod( - name=pod_name, - namespace=namespace, - client=admin_client, - ) as p: - p.wait_for_status(status="Running") - p.wait_for_condition(condition="Ready", status="True") - yield p + containers = [pod_name] + if istio: + containers.append("istio-proxy") + + pod = Pod(name=pod_name, namespace=namespace, client=admin_client) + pod.wait_for_status(status="Running") + pod.wait_for_condition(condition="Ready", status="True") + return pod def b64_encoded_string(string_to_encode: str) -> str: diff --git a/tests/model_serving/model_server/storage/pvc/utils.py b/tests/model_serving/model_server/storage/pvc/utils.py index 7dfeeae..3b977a7 100644 --- a/tests/model_serving/model_server/storage/pvc/utils.py +++ b/tests/model_serving/model_server/storage/pvc/utils.py @@ -19,6 +19,15 @@ def create_isvc( storage_path: Optional[str] = None, min_replicas: int = 1, wait: bool = True, +) -> Generator[InferenceService, Any, Any]: + predictor_storage = { + "minReplicas": min_replicas, + "model": { + "modelFormat": {"name": model_format}, + "version": "1", + "runtime": runtime, + }, + } ) -> Generator[InferenceService, Any, Any]: predictor_storage = { "minReplicas": min_replicas, @@ -29,12 +38,9 @@ def create_isvc( }, } if storage_uri: - predictor_storage["model"]["storageUri"] = storage_uri + predictor_storage["model"]["storageUri"] = storage_uri # type: ignore elif storage_key and storage_path: - predictor_storage["storage"] = { - "key": storage_key, - "path": storage_path, - } + predictor_storage["model"]["storage"] = {"key": storage_key, "path": storage_path} # type: ignore else: raise MissingStorageArgument(storage_uri, storage_key, storage_path) @@ -49,6 +55,7 @@ def create_isvc( "serving.kserve.io/deploymentMode": deployment_mode, }, predictor=predictor_storage, + wait_for_resource=wait, ) as inference_service: if wait: inference_service.wait_for_condition( From c67627ade3f77d8cefc64777f75f9496b256494c Mon Sep 17 00:00:00 2001 From: lugi0 Date: Thu, 14 Nov 2024 10:35:41 +0100 Subject: [PATCH 20/31] Fix typo in gitignore Signed-off-by: lugi0 --- .gitignore | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.gitignore b/.gitignore index b6f77c8..c9d5b3b 100644 --- a/.gitignore +++ b/.gitignore @@ -162,7 +162,3 @@ cython_debug/ # OS generated files # .DS_Store .DS_Store? - -# OS generated files # -.DS_Store -.DS_Store? From 38b1f728c8d82955805212d36cf8c47f03d17a10 Mon Sep 17 00:00:00 2001 From: lugi0 Date: Thu, 14 Nov 2024 10:43:01 +0100 Subject: [PATCH 21/31] Remove duplicated lines Signed-off-by: lugi0 --- .../model_server/private_endpoint/conftest.py | 8 -------- .../model_server/private_endpoint/utils.py | 11 ----------- tests/model_serving/model_server/storage/pvc/utils.py | 9 --------- 3 files changed, 28 deletions(-) diff --git a/tests/model_serving/model_server/private_endpoint/conftest.py b/tests/model_serving/model_server/private_endpoint/conftest.py index 404d006..0f40a2e 100644 --- a/tests/model_serving/model_server/private_endpoint/conftest.py +++ b/tests/model_serving/model_server/private_endpoint/conftest.py @@ -24,13 +24,11 @@ @pytest.fixture(scope="module") -def endpoint_namespace(admin_client: DynamicClient) -> Generator[Namespace, None, None]: def endpoint_namespace(admin_client: DynamicClient) -> Generator[Namespace, None, None]: yield from create_ns(admin_client=admin_client, name="endpoint-namespace") @pytest.fixture(scope="module") -def diff_namespace(admin_client: DynamicClient) -> Generator[Namespace, None, None]: def diff_namespace(admin_client: DynamicClient) -> Generator[Namespace, None, None]: yield from create_ns(admin_client=admin_client, name="diff-namespace") @@ -39,7 +37,6 @@ def diff_namespace(admin_client: DynamicClient) -> Generator[Namespace, None, No def endpoint_sr( admin_client: DynamicClient, endpoint_namespace: Namespace, -) -> Generator[ServingRuntime, None, None]: ) -> Generator[ServingRuntime, None, None]: with ServingRuntimeFromTemplate( client=admin_client, @@ -55,7 +52,6 @@ def endpoint_s3_secret( admin_client: DynamicClient, endpoint_namespace: Namespace, aws_access_key_id: str, - aws_access_key_id: str, aws_secret_access_key: str, s3_bucket_name_wisdom: str, ) -> Generator[Secret, None, None]: @@ -83,7 +79,6 @@ def endpoint_isvc( endpoint_s3_secret: Secret, storage_config_secret: Secret, endpoint_namespace: Namespace, -) -> Generator[InferenceService, None, None]: ) -> Generator[InferenceService, None, None]: with create_isvc( client=admin_client, @@ -128,9 +123,6 @@ def storage_config_secret( @pytest.fixture() -def service_mesh_member( - admin_client: DynamicClient, diff_namespace: Namespace -) -> Generator[ServiceMeshMember, None, None]: def service_mesh_member( admin_client: DynamicClient, diff_namespace: Namespace ) -> Generator[ServiceMeshMember, None, None]: diff --git a/tests/model_serving/model_server/private_endpoint/utils.py b/tests/model_serving/model_server/private_endpoint/utils.py index 3670834..63019da 100644 --- a/tests/model_serving/model_server/private_endpoint/utils.py +++ b/tests/model_serving/model_server/private_endpoint/utils.py @@ -18,27 +18,16 @@ class ProtocolNotSupported(Exception): def __init__(self, protocol: str): self.protocol = protocol - def __str__(self) -> str: return f"Protocol {self.protocol} is not supported" - - class MissingStorageArgument(Exception): def __init__( self, storageUri: Optional[str], storage_key: Optional[str], storage_path: Optional[str], - ): - self.storageUri = storageUri - self.storage_key = storage_key - self.storage_path = storage_path - self, - storageUri: Optional[str], - storage_key: Optional[str], - storage_path: Optional[str], ): self.storageUri = storageUri self.storage_key = storage_key diff --git a/tests/model_serving/model_server/storage/pvc/utils.py b/tests/model_serving/model_server/storage/pvc/utils.py index 3b977a7..fa26909 100644 --- a/tests/model_serving/model_server/storage/pvc/utils.py +++ b/tests/model_serving/model_server/storage/pvc/utils.py @@ -19,15 +19,6 @@ def create_isvc( storage_path: Optional[str] = None, min_replicas: int = 1, wait: bool = True, -) -> Generator[InferenceService, Any, Any]: - predictor_storage = { - "minReplicas": min_replicas, - "model": { - "modelFormat": {"name": model_format}, - "version": "1", - "runtime": runtime, - }, - } ) -> Generator[InferenceService, Any, Any]: predictor_storage = { "minReplicas": min_replicas, From c9ade8a7368bc4c9bd08820a3f95de278fb94072 Mon Sep 17 00:00:00 2001 From: lugi0 Date: Fri, 22 Nov 2024 15:56:00 +0100 Subject: [PATCH 22/31] Address review comments Signed-off-by: lugi0 --- conftest.py | 12 ++++----- .../private_endpoint/constants.py | 2 +- .../model_server/private_endpoint/infra.py | 4 +-- .../model_server/private_endpoint/utils.py | 26 ++++++++++++------- .../model_server/storage/pvc/utils.py | 17 +++++++----- 5 files changed, 36 insertions(+), 25 deletions(-) diff --git a/conftest.py b/conftest.py index 5eb847d..9d9e559 100644 --- a/conftest.py +++ b/conftest.py @@ -34,9 +34,9 @@ def pytest_addoption(parser): ) buckets_group.addoption( - "--ci-s3-bucket-name-wisdom", - default=os.environ.get("CI_S3_BUCKET_NAME_WISDOM"), - help="Ci S3 bucket name - wisdom", + "--models-s3-bucket-name", + default=os.environ.get("MODELS_S3_BUCKET_NAME"), + help="Models S3 bucket name", ) @@ -95,11 +95,11 @@ def pytest_sessionfinish(session, exitstatus): @pytest.fixture(scope="session") def s3_bucket_name_wisdom(pytestconfig: pytest.Config) -> Optional[str]: - wisdom_bucket = pytestconfig.option.ci_s3_bucket_name_wisdom + wisdom_bucket = pytestconfig.option.models_s3_bucket_name if not wisdom_bucket: raise ValueError( - "Bucket name for wisdom bucket is not defined." - "Either pass with `--ci-s3-bucket-name-wisdom` or set `CI_S3_BUCKET_NAME_WISDOM` environment variable" + "Bucket name for the models bucket is not defined." + "Either pass with `--models-s3-bucket-name` or set `MODELS_S3_BUCKET_NAME` environment variable" ) return wisdom_bucket diff --git a/tests/model_serving/model_server/private_endpoint/constants.py b/tests/model_serving/model_server/private_endpoint/constants.py index 150b9f2..ba385a4 100644 --- a/tests/model_serving/model_server/private_endpoint/constants.py +++ b/tests/model_serving/model_server/private_endpoint/constants.py @@ -1,2 +1,2 @@ AWS_REGION_EAST_2: str = "us-east-2" -AWS_ENDPOINT_EAST_2: str = "https://s3.us-east-2.amazonaws.com/" +AWS_ENDPOINT_EAST_2: str = f"https://s3.{AWS_REGION_EAST_2}.amazonaws.com/" diff --git a/tests/model_serving/model_server/private_endpoint/infra.py b/tests/model_serving/model_server/private_endpoint/infra.py index c3aa19e..38b5d07 100644 --- a/tests/model_serving/model_server/private_endpoint/infra.py +++ b/tests/model_serving/model_server/private_endpoint/infra.py @@ -6,10 +6,10 @@ def create_ns( name: str, - labels: Optional[Dict[str, str]] = None, - admin_client: DynamicClient = None, + admin_client: DynamicClient, teardown: bool = True, delete_timeout: int = 6 * 10, + labels: Optional[Dict[str, str]] = None, ) -> Generator[Namespace, None, None]: with Namespace( client=admin_client, diff --git a/tests/model_serving/model_server/private_endpoint/utils.py b/tests/model_serving/model_server/private_endpoint/utils.py index 63019da..6b9051a 100644 --- a/tests/model_serving/model_server/private_endpoint/utils.py +++ b/tests/model_serving/model_server/private_endpoint/utils.py @@ -22,7 +22,7 @@ def __str__(self) -> str: return f"Protocol {self.protocol} is not supported" -class MissingStorageArgument(Exception): +class InvalidStorageArgument(Exception): def __init__( self, storageUri: Optional[str], @@ -41,7 +41,6 @@ def __str__(self) -> str: "storage_path: {self.storage_path} In order to create a valid ISVC you need to specify either a storageUri value or both a storage key and a storage path. - or both a storage key and a storage path. """ return msg @@ -60,15 +59,12 @@ def curl_from_pod( endpoint: str, protocol: str = "http", ) -> str: + if protocol not in ("https", "http"): + raise ProtocolNotSupported(protocol) + host = isvc.instance.status.address.url if protocol == "http": - parsed = urlparse(isvc.instance.status.address.url) + parsed = urlparse(host) host = parsed._replace(scheme="http").geturl() - - elif protocol == "https": - host = isvc.instance.status.address.url - else: - raise ProtocolNotSupported(protocol) - return pod.execute(command=shlex.split(f"curl -k {host}/{endpoint}"), ignore_rc=True) @@ -99,6 +95,18 @@ def create_sidecar_pod( def b64_encoded_string(string_to_encode: str) -> str: + """Returns openshift compliant base64 encoding of a string + + encodes the input string to bytes-like, encodes the bytes-like to base 64, + decodes the b64 to a string and returns it. This is needed for openshift + resources expecting b64 encoded values in the yaml. + + Args: + string_to_encode: The string to encode in base64 + + Returns: + A base64 encoded string that is compliant with openshift's yaml format + """ # encodes the string to bytes-like, encodes the bytes-like to base 64, decodes the b64 to a string and returns it # needed for openshift resources expecting b64 encoded values in the yaml return base64.b64encode(string_to_encode.encode()).decode() diff --git a/tests/model_serving/model_server/storage/pvc/utils.py b/tests/model_serving/model_server/storage/pvc/utils.py index fa26909..3ebc0fd 100644 --- a/tests/model_serving/model_server/storage/pvc/utils.py +++ b/tests/model_serving/model_server/storage/pvc/utils.py @@ -3,7 +3,7 @@ from kubernetes.dynamic import DynamicClient from ocp_resources.inference_service import InferenceService -from tests.model_serving.model_server.private_endpoint.utils import MissingStorageArgument +from tests.model_serving.model_server.private_endpoint.utils import InvalidStorageArgument @contextmanager @@ -20,7 +20,7 @@ def create_isvc( min_replicas: int = 1, wait: bool = True, ) -> Generator[InferenceService, Any, Any]: - predictor_storage = { + predictor_dict = { "minReplicas": min_replicas, "model": { "modelFormat": {"name": model_format}, @@ -28,12 +28,15 @@ def create_isvc( "runtime": runtime, }, } - if storage_uri: - predictor_storage["model"]["storageUri"] = storage_uri # type: ignore + # "type:ignore" is needed because otherwise mypy will complain about "Unsupported target for indexed assignment ("object")" + if storage_uri and storage_key and storage_path: + raise InvalidStorageArgument(storage_uri, storage_key, storage_path) + elif storage_uri: + predictor_dict["model"]["storageUri"] = storage_uri # type: ignore elif storage_key and storage_path: - predictor_storage["model"]["storage"] = {"key": storage_key, "path": storage_path} # type: ignore + predictor_dict["model"]["storage"] = {"key": storage_key, "path": storage_path} # type: ignore else: - raise MissingStorageArgument(storage_uri, storage_key, storage_path) + raise InvalidStorageArgument(storage_uri, storage_key, storage_path) with InferenceService( client=client, @@ -45,7 +48,7 @@ def create_isvc( "sidecar.istio.io/rewriteAppHTTPProbers": "true", "serving.kserve.io/deploymentMode": deployment_mode, }, - predictor=predictor_storage, + predictor=predictor_dict, wait_for_resource=wait, ) as inference_service: if wait: From 22619a249f7f2b33563b1dd7d8d666f1e3434747 Mon Sep 17 00:00:00 2001 From: lugi0 Date: Fri, 22 Nov 2024 16:42:43 +0100 Subject: [PATCH 23/31] fix broken import Signed-off-by: lugi0 --- tests/model_serving/model_server/private_endpoint/conftest.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/model_serving/model_server/private_endpoint/conftest.py b/tests/model_serving/model_server/private_endpoint/conftest.py index 0f40a2e..a0ba2b2 100644 --- a/tests/model_serving/model_server/private_endpoint/conftest.py +++ b/tests/model_serving/model_server/private_endpoint/conftest.py @@ -12,6 +12,7 @@ from utilities.serving_runtime import ServingRuntimeFromTemplate from tests.model_serving.model_server.storage.pvc.utils import create_isvc +from tests.model_serving.model_server.storage.pvc.conftest import aws_access_key_id, aws_secret_access_key from tests.model_serving.model_server.private_endpoint.utils import create_sidecar_pod, get_flan_pod, b64_encoded_string from tests.model_serving.model_server.private_endpoint.infra import create_ns from tests.model_serving.model_server.private_endpoint.constants import ( From 8e6f07d6c2013cfa19ec8a6527492cb83ea63e68 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 22 Nov 2024 15:43:03 +0000 Subject: [PATCH 24/31] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tests/model_serving/model_server/private_endpoint/conftest.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/model_serving/model_server/private_endpoint/conftest.py b/tests/model_serving/model_server/private_endpoint/conftest.py index a0ba2b2..0f40a2e 100644 --- a/tests/model_serving/model_server/private_endpoint/conftest.py +++ b/tests/model_serving/model_server/private_endpoint/conftest.py @@ -12,7 +12,6 @@ from utilities.serving_runtime import ServingRuntimeFromTemplate from tests.model_serving.model_server.storage.pvc.utils import create_isvc -from tests.model_serving.model_server.storage.pvc.conftest import aws_access_key_id, aws_secret_access_key from tests.model_serving.model_server.private_endpoint.utils import create_sidecar_pod, get_flan_pod, b64_encoded_string from tests.model_serving.model_server.private_endpoint.infra import create_ns from tests.model_serving.model_server.private_endpoint.constants import ( From 55be8994fe1dcf02f589d7b0fe9b4919b5b5add7 Mon Sep 17 00:00:00 2001 From: lugi0 Date: Mon, 25 Nov 2024 16:23:17 +0100 Subject: [PATCH 25/31] Address PR comments, improve typing, remove mypy.ini, update CONTRIBUTING.MD Signed-off-by: lugi0 --- CONTRIBUTING.md | 5 + conftest.py | 58 +++++---- mypy.ini | 8 -- pyproject.toml | 1 + tests/conftest.py | 98 ++++++++++++++- tests/model_serving/constants.py | 2 + .../model_server/private_endpoint/conftest.py | 117 +++++++++--------- .../private_endpoint/constants.py | 2 - .../test_kserve_private_endpoint.py | 10 +- .../model_server/private_endpoint/utils.py | 36 +++--- .../model_server/storage/pvc/conftest.py | 84 +++---------- .../storage/pvc/test_kserve_pvc_rwx.py | 3 +- .../model_server/storage/pvc/utils.py | 18 ++- tests/utils.py | 4 +- 14 files changed, 254 insertions(+), 192 deletions(-) delete mode 100644 mypy.ini create mode 100644 tests/model_serving/constants.py delete mode 100644 tests/model_serving/model_server/private_endpoint/constants.py diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 11d6d84..54088e9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -31,3 +31,8 @@ pre-commit install ## General - Add typing to new code; typing is enforced using [mypy](https://mypy-lang.org/) + - Rules are defined in [our pyproject.toml file](//pyproject.toml#L10) + +If you use Visual Studio Code as your IDE, we recommend using the [Mypy Type Checker](https://marketplace.visualstudio.com/items?itemName=ms-python.mypy-type-checker) extension. +After installing it, make sure to update the `Mypy-type-checkers: Args` setting +to `"mypy-type-checker.args" = ["--config-file=pyproject.toml"]`. diff --git a/conftest.py b/conftest.py index 9d9e559..ad52469 100644 --- a/conftest.py +++ b/conftest.py @@ -2,8 +2,9 @@ import os import pathlib import shutil -import pytest -from typing import Optional +from pytest import Parser, Session, FixtureRequest, FixtureDef, Item, Config, CollectReport +from _pytest.terminal import TerminalReporter +from typing import Optional, Any from utilities.logger import separator, setup_logging @@ -12,7 +13,7 @@ BASIC_LOGGER = logging.getLogger("basic") -def pytest_addoption(parser): +def pytest_addoption(parser: Parser) -> None: aws_group = parser.getgroup(name="AWS") buckets_group = parser.getgroup(name="Buckets") @@ -33,14 +34,34 @@ def pytest_addoption(parser): "--ci-s3-bucket-name", default=os.environ.get("CI_S3_BUCKET_NAME"), help="Ci S3 bucket name" ) + buckets_group.addoption( + "--ci-s3-bucket-region", default=os.environ.get("CI_S3_BUCKET_REGION"), help="Ci S3 bucket region" + ) + + buckets_group.addoption( + "--ci-s3-bucket-endpoint", default=os.environ.get("CI_S3_BUCKET_ENDPOINT"), help="Ci S3 bucket endpoint" + ) + buckets_group.addoption( "--models-s3-bucket-name", default=os.environ.get("MODELS_S3_BUCKET_NAME"), help="Models S3 bucket name", ) + buckets_group.addoption( + "--models-s3-bucket-region", + default=os.environ.get("MODELS_S3_BUCKET_REGION"), + help="Models S3 bucket region", + ) -def pytest_sessionstart(session): + buckets_group.addoption( + "--models-s3-bucket-endpoint", + default=os.environ.get("MODELS_S3_BUCKET_ENDPOINT"), + help="Models S3 bucket endpoint", + ) + + +def pytest_sessionstart(session: Session) -> None: tests_log_file = session.config.getoption("log_file") or "pytest-tests.log" if os.path.exists(tests_log_file): pathlib.Path(tests_log_file).unlink() @@ -51,24 +72,24 @@ def pytest_sessionstart(session): ) -def pytest_fixture_setup(fixturedef, request): +def pytest_fixture_setup(fixturedef: FixtureDef[Any], request: FixtureRequest) -> None: LOGGER.info(f"Executing {fixturedef.scope} fixture: {fixturedef.argname}") -def pytest_runtest_setup(item): +def pytest_runtest_setup(item: Item) -> None: BASIC_LOGGER.info(f"\n{separator(symbol_='-', val=item.name)}") BASIC_LOGGER.info(f"{separator(symbol_='-', val='SETUP')}") -def pytest_runtest_call(item): +def pytest_runtest_call(item: Item) -> None: BASIC_LOGGER.info(f"{separator(symbol_='-', val='CALL')}") -def pytest_runtest_teardown(item): +def pytest_runtest_teardown(item: Item) -> None: BASIC_LOGGER.info(f"{separator(symbol_='-', val='TEARDOWN')}") -def pytest_report_teststatus(report, config): +def pytest_report_teststatus(report: CollectReport, config: Config) -> None: test_name = report.head_line when = report.when call_str = "call" @@ -86,20 +107,9 @@ def pytest_report_teststatus(report, config): BASIC_LOGGER.info(f"\nTEST: {test_name} STATUS: \033[0;31mFAILED\033[0m") -def pytest_sessionfinish(session, exitstatus): +def pytest_sessionfinish(session: Session, exitstatus: int) -> None: shutil.rmtree(path=session.config.option.basetemp, ignore_errors=True) - reporter = session.config.pluginmanager.get_plugin("terminalreporter") - reporter.summary_stats() - - -@pytest.fixture(scope="session") -def s3_bucket_name_wisdom(pytestconfig: pytest.Config) -> Optional[str]: - wisdom_bucket = pytestconfig.option.models_s3_bucket_name - if not wisdom_bucket: - raise ValueError( - "Bucket name for the models bucket is not defined." - "Either pass with `--models-s3-bucket-name` or set `MODELS_S3_BUCKET_NAME` environment variable" - ) - - return wisdom_bucket + reporter: Optional[TerminalReporter] = session.config.pluginmanager.get_plugin("terminalreporter") + if reporter: + reporter.summary_stats() diff --git a/mypy.ini b/mypy.ini deleted file mode 100644 index 815166a..0000000 --- a/mypy.ini +++ /dev/null @@ -1,8 +0,0 @@ -[mypy] -check_untyped_defs = true -disallow_any_generics = true -disallow_incomplete_defs = true -disallow_untyped_defs = true -no_implicit_optional = true -show_error_codes = true -warn_unused_ignores = true diff --git a/pyproject.toml b/pyproject.toml index 130cc9c..ffce353 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,6 +15,7 @@ disallow_untyped_defs = true no_implicit_optional = true show_error_codes = true warn_unused_ignores = true +ignore_missing_imports = true [tool.uv] dev-dependencies = [ diff --git a/tests/conftest.py b/tests/conftest.py index aeb08d9..650bc1a 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,4 +1,7 @@ +from typing import Tuple, Any, Generator + import pytest +from pytest import FixtureRequest, Config from kubernetes.dynamic import DynamicClient from ocp_resources.namespace import Namespace from ocp_resources.resource import get_client @@ -12,6 +15,99 @@ def admin_client() -> DynamicClient: @pytest.fixture(scope="class") -def model_namespace(request, admin_client: DynamicClient) -> Namespace: +def model_namespace(request: FixtureRequest, admin_client: DynamicClient) -> Generator[Namespace, Any, Any]: with create_ns(client=admin_client, name=request.param["name"]) as ns: yield ns + + +@pytest.fixture(scope="session") +def aws_access_key_id(pytestconfig: Config) -> str: + access_key = pytestconfig.option.aws_access_key_id + if not access_key: + raise ValueError( + "AWS access key id is not set. " + "Either pass with `--aws-access-key-id` or set `AWS_ACCESS_KEY_ID` environment variable" + ) + return access_key + + +@pytest.fixture(scope="session") +def aws_secret_access_key(pytestconfig: Config) -> str: + secret_access_key = pytestconfig.option.aws_secret_access_key + if not secret_access_key: + raise ValueError( + "AWS secret access key is not set. " + "Either pass with `--aws-secret-access-key` or set `AWS_SECRET_ACCESS_KEY` environment variable" + ) + return secret_access_key + + +@pytest.fixture(scope="session") +def valid_aws_config(aws_access_key_id: str, aws_secret_access_key: str) -> Tuple[str, str]: + return aws_access_key_id, aws_secret_access_key + + +@pytest.fixture(scope="session") +def ci_s3_bucket_name(pytestconfig: Config) -> str: + bucket_name = pytestconfig.option.ci_s3_bucket_name + if not bucket_name: + raise ValueError( + "CI S3 bucket name is not set. " + "Either pass with `--ci-s3-bucket-name` or set `CI_S3_BUCKET_NAME` environment variable" + ) + return bucket_name + + +@pytest.fixture(scope="session") +def ci_s3_bucket_region(pytestconfig: pytest.Config) -> str: + ci_bucket_region = pytestconfig.option.ci_s3_bucket_region + if not ci_bucket_region: + raise ValueError( + "Bucket name for the models bucket is not defined." + "Either pass with `--ci-s3-bucket-region` or set `CI_S3_BUCKET_REGION` environment variable" + ) + return ci_bucket_region + + +@pytest.fixture(scope="session") +def ci_s3_bucket_endpoint(pytestconfig: pytest.Config) -> str: + ci_bucket_endpoint = pytestconfig.option.ci_s3_bucket_endpoint + if not ci_bucket_endpoint: + raise ValueError( + "Bucket name for the models bucket is not defined." + "Either pass with `--ci-s3-bucket-endpoint` or set `CI_S3_BUCKET_ENDPOINT` environment variable" + ) + return ci_bucket_endpoint + + +@pytest.fixture(scope="session") +def models_s3_bucket_name(pytestconfig: pytest.Config) -> str: + models_bucket = pytestconfig.option.models_s3_bucket_name + if not models_bucket: + raise ValueError( + "Bucket name for the models bucket is not defined." + "Either pass with `--models-s3-bucket-name` or set `MODELS_S3_BUCKET_NAME` environment variable" + ) + return models_bucket + + +@pytest.fixture(scope="session") +def models_s3_bucket_region(pytestconfig: pytest.Config) -> str: + models_bucket_region = pytestconfig.option.models_s3_bucket_region + if not models_bucket_region: + raise ValueError( + "Bucket name for the models bucket is not defined." + "Either pass with `--models-s3-bucket-region` or set `MODELS_S3_BUCKET_REGION` environment variable" + ) + return models_bucket_region + + +@pytest.fixture(scope="session") +def models_s3_bucket_endpoint(pytestconfig: pytest.Config) -> str: + models_bucket_endpoint = pytestconfig.option.models_s3_bucket_endpoint + if not models_bucket_endpoint: + raise ValueError( + "Bucket name for the models bucket is not defined." + "Either pass with `--models-s3-bucket-endpoint` or set `MODELS_S3_BUCKET_ENDPOINT` environment variable" + ) + return models_bucket_endpoint diff --git a/tests/model_serving/constants.py b/tests/model_serving/constants.py new file mode 100644 index 0000000..2b07f37 --- /dev/null +++ b/tests/model_serving/constants.py @@ -0,0 +1,2 @@ +KSERVE_SERVERLESS: str = "Serverless" +KSERVE_RAWDEPLOYMENT: str = "RawDeployment" diff --git a/tests/model_serving/model_server/private_endpoint/conftest.py b/tests/model_serving/model_server/private_endpoint/conftest.py index 0f40a2e..277a709 100644 --- a/tests/model_serving/model_server/private_endpoint/conftest.py +++ b/tests/model_serving/model_server/private_endpoint/conftest.py @@ -1,39 +1,39 @@ import json import pytest -from typing import Generator +from typing import Generator, Any from ocp_resources.inference_service import InferenceService from ocp_resources.secret import Secret from ocp_resources.namespace import Namespace from ocp_resources.pod import Pod from simple_logger.logger import get_logger -from ocp_resources.service_mesh_member import ServiceMeshMember from ocp_resources.serving_runtime import ServingRuntime from kubernetes.dynamic import DynamicClient from utilities.serving_runtime import ServingRuntimeFromTemplate from tests.model_serving.model_server.storage.pvc.utils import create_isvc -from tests.model_serving.model_server.private_endpoint.utils import create_sidecar_pod, get_flan_pod, b64_encoded_string -from tests.model_serving.model_server.private_endpoint.infra import create_ns -from tests.model_serving.model_server.private_endpoint.constants import ( - AWS_REGION_EAST_2, - AWS_ENDPOINT_EAST_2, +from tests.model_serving.model_server.private_endpoint.utils import ( + create_sidecar_pod, + get_flan_deployment, + b64_encoded_string, ) +from tests.model_serving.model_server.private_endpoint.infra import create_ns +from tests.model_serving.constants import KSERVE_SERVERLESS LOGGER = get_logger(name=__name__) -@pytest.fixture(scope="module") +@pytest.fixture(scope="session") def endpoint_namespace(admin_client: DynamicClient) -> Generator[Namespace, None, None]: yield from create_ns(admin_client=admin_client, name="endpoint-namespace") -@pytest.fixture(scope="module") +@pytest.fixture(scope="session") def diff_namespace(admin_client: DynamicClient) -> Generator[Namespace, None, None]: yield from create_ns(admin_client=admin_client, name="diff-namespace") -@pytest.fixture() +@pytest.fixture(scope="session") def endpoint_sr( admin_client: DynamicClient, endpoint_namespace: Namespace, @@ -47,19 +47,21 @@ def endpoint_sr( yield model_runtime -@pytest.fixture() +@pytest.fixture(scope="session") def endpoint_s3_secret( admin_client: DynamicClient, endpoint_namespace: Namespace, aws_access_key_id: str, aws_secret_access_key: str, - s3_bucket_name_wisdom: str, + models_s3_bucket_name: str, + models_s3_bucket_region: str, + models_s3_bucket_endpoint: str, ) -> Generator[Secret, None, None]: data = { "AWS_ACCESS_KEY_ID": b64_encoded_string(aws_access_key_id), - "AWS_DEFAULT_REGION": b64_encoded_string(AWS_REGION_EAST_2), - "AWS_S3_BUCKET": b64_encoded_string(s3_bucket_name_wisdom), - "AWS_S3_ENDPOINT": b64_encoded_string(AWS_ENDPOINT_EAST_2), + "AWS_DEFAULT_REGION": b64_encoded_string(models_s3_bucket_region), + "AWS_S3_BUCKET": b64_encoded_string(models_s3_bucket_name), + "AWS_S3_ENDPOINT": b64_encoded_string(models_s3_bucket_endpoint), "AWS_SECRET_ACCESS_KEY": b64_encoded_string(aws_secret_access_key), } with Secret( @@ -72,7 +74,7 @@ def endpoint_s3_secret( yield secret -@pytest.fixture() +@pytest.fixture(scope="session") def endpoint_isvc( admin_client: DynamicClient, endpoint_sr: ServingRuntime, @@ -84,7 +86,7 @@ def endpoint_isvc( client=admin_client, name="test", namespace=endpoint_namespace.name, - deployment_mode="Serverless", + deployment_mode=KSERVE_SERVERLESS, storage_key="endpoint-s3-secret", storage_path="flan-t5-small/flan-t5-small-caikit", model_format="caikit", @@ -93,21 +95,23 @@ def endpoint_isvc( yield isvc -@pytest.fixture() +@pytest.fixture(scope="session") def storage_config_secret( admin_client: DynamicClient, endpoint_namespace: Namespace, endpoint_s3_secret: Secret, aws_access_key_id: str, aws_secret_access_key: str, - s3_bucket_name_wisdom: str, + models_s3_bucket_name: str, + models_s3_bucket_region: str, + models_s3_bucket_endpoint: str, ) -> Generator[Secret, None, None]: secret = { "access_key_id": aws_access_key_id, - "bucket": s3_bucket_name_wisdom, - "default_bucket": s3_bucket_name_wisdom, - "endpoint_url": AWS_ENDPOINT_EAST_2, - "region": AWS_REGION_EAST_2, + "bucket": models_s3_bucket_name, + "default_bucket": models_s3_bucket_name, + "endpoint_url": models_s3_bucket_endpoint, + "region": models_s3_bucket_region, "secret_access_key": aws_secret_access_key, "type": "s3", } @@ -123,73 +127,64 @@ def storage_config_secret( @pytest.fixture() -def service_mesh_member( - admin_client: DynamicClient, diff_namespace: Namespace -) -> Generator[ServiceMeshMember, None, None]: - with ServiceMeshMember( - client=admin_client, - namespace=diff_namespace.name, - name="default", - control_plane_ref={"name": "data-science-smcp", "namespace": "istio-system"}, - wait_for_resource=True, - ) as smm: - yield smm - - -@pytest.fixture() -def endpoint_pod_with_istio_sidecar(admin_client: DynamicClient, endpoint_namespace: Namespace) -> Pod: - pod = create_sidecar_pod( +def endpoint_pod_with_istio_sidecar( + admin_client: DynamicClient, endpoint_namespace: Namespace +) -> Generator[Pod, Any, Any]: + with create_sidecar_pod( admin_client=admin_client, namespace=endpoint_namespace.name, istio=True, pod_name="test-with-istio", - ) - yield pod - pod.clean_up() + ) as pod: + yield pod @pytest.fixture() -def endpoint_pod_without_istio_sidecar(admin_client: DynamicClient, endpoint_namespace: Namespace) -> Pod: - pod = create_sidecar_pod( +def endpoint_pod_without_istio_sidecar( + admin_client: DynamicClient, endpoint_namespace: Namespace +) -> Generator[Pod, Any, Any]: + with create_sidecar_pod( admin_client=admin_client, namespace=endpoint_namespace.name, istio=False, pod_name="test", - ) - yield pod - pod.clean_up() + ) as pod: + yield pod @pytest.fixture() -def diff_pod_with_istio_sidecar(admin_client: DynamicClient, diff_namespace: Namespace) -> Pod: - pod = create_sidecar_pod( +def diff_pod_with_istio_sidecar( + admin_client: DynamicClient, + diff_namespace: Namespace, +) -> Generator[Pod, Any, Any]: + with create_sidecar_pod( admin_client=admin_client, namespace=diff_namespace.name, istio=True, pod_name="test-with-istio", - ) - yield pod - pod.clean_up() + ) as pod: + yield pod @pytest.fixture() -def diff_pod_without_istio_sidecar(admin_client: DynamicClient, diff_namespace: Namespace) -> Pod: - pod = create_sidecar_pod( +def diff_pod_without_istio_sidecar( + admin_client: DynamicClient, + diff_namespace: Namespace, +) -> Generator[Pod, Any, Any]: + with create_sidecar_pod( admin_client=admin_client, namespace=diff_namespace.name, istio=False, pod_name="test", - ) - yield pod - pod.clean_up() + ) as pod: + yield pod @pytest.fixture() -def running_flan_pod(admin_client: DynamicClient, endpoint_isvc: InferenceService) -> None: - predictor_pod = get_flan_pod( +def ready_predictor(admin_client: DynamicClient, endpoint_isvc: InferenceService) -> None: + predictor_deployment = get_flan_deployment( namespace=endpoint_isvc.namespace, client=admin_client, name_prefix=endpoint_isvc.name, ) - predictor_pod.wait_for_status(status="Running") - predictor_pod.wait_for_condition(condition="Ready", status="True") + predictor_deployment.wait_for_replicas() diff --git a/tests/model_serving/model_server/private_endpoint/constants.py b/tests/model_serving/model_server/private_endpoint/constants.py deleted file mode 100644 index ba385a4..0000000 --- a/tests/model_serving/model_server/private_endpoint/constants.py +++ /dev/null @@ -1,2 +0,0 @@ -AWS_REGION_EAST_2: str = "us-east-2" -AWS_ENDPOINT_EAST_2: str = f"https://s3.{AWS_REGION_EAST_2}.amazonaws.com/" diff --git a/tests/model_serving/model_server/private_endpoint/test_kserve_private_endpoint.py b/tests/model_serving/model_server/private_endpoint/test_kserve_private_endpoint.py index c1483a9..78fcfb6 100644 --- a/tests/model_serving/model_server/private_endpoint/test_kserve_private_endpoint.py +++ b/tests/model_serving/model_server/private_endpoint/test_kserve_private_endpoint.py @@ -4,7 +4,7 @@ from ocp_resources.namespace import Namespace from ocp_resources.inference_service import InferenceService from ocp_resources.pod import Pod -from ocp_resources.service_mesh_member import ServiceMeshMember +from ocp_resources.deployment import Deployment from tests.model_serving.model_server.private_endpoint.utils import curl_from_pod @@ -13,12 +13,12 @@ class TestKserveInternalEndpoint: def test_deploy_model_state_loaded( - self: Self, endpoint_namespace: Namespace, endpoint_isvc: InferenceService, running_flan_pod: Pod + self: Self, endpoint_namespace: Namespace, endpoint_isvc: InferenceService, ready_predictor: Deployment ) -> None: assert endpoint_isvc.instance.status.modelStatus.states.activeModelState == "Loaded" def test_deploy_model_url( - self: Self, endpoint_namespace: Namespace, endpoint_isvc: InferenceService, running_flan_pod: Pod + self: Self, endpoint_namespace: Namespace, endpoint_isvc: InferenceService, ready_predictor: Deployment ) -> None: assert ( endpoint_isvc.instance.status.address.url @@ -29,7 +29,6 @@ def test_curl_with_istio_same_ns( self: Self, endpoint_isvc: InferenceService, endpoint_pod_with_istio_sidecar: Pod, - service_mesh_member: ServiceMeshMember, ) -> None: LOGGER.info("Testing curl from the same namespace with a pod part of the service mesh") @@ -44,7 +43,6 @@ def test_curl_with_istio_diff_ns( self: Self, endpoint_isvc: InferenceService, diff_pod_with_istio_sidecar: Pod, - service_mesh_member: ServiceMeshMember, ) -> None: LOGGER.info("Testing curl from a different namespace with a pod part of the service mesh") @@ -60,7 +58,6 @@ def test_curl_outside_istio_same_ns( self: Self, endpoint_isvc: InferenceService, endpoint_pod_without_istio_sidecar: Pod, - service_mesh_member: ServiceMeshMember, ) -> None: LOGGER.info("Testing curl from the same namespace with a pod not part of the service mesh") @@ -76,7 +73,6 @@ def test_curl_outside_istio_diff_ns( self: Self, endpoint_isvc: InferenceService, diff_pod_without_istio_sidecar: Pod, - service_mesh_member: ServiceMeshMember, ) -> None: LOGGER.info("Testing curl from a different namespace with a pod not part of the service mesh") diff --git a/tests/model_serving/model_server/private_endpoint/utils.py b/tests/model_serving/model_server/private_endpoint/utils.py index 6b9051a..e012cb6 100644 --- a/tests/model_serving/model_server/private_endpoint/utils.py +++ b/tests/model_serving/model_server/private_endpoint/utils.py @@ -1,9 +1,11 @@ import shlex import base64 -from typing import Optional +from typing import Optional, Any, Generator from urllib.parse import urlparse +from contextlib import contextmanager from ocp_resources.pod import Pod +from ocp_resources.deployment import Deployment from kubernetes.dynamic.client import DynamicClient from kubernetes.dynamic.exceptions import ResourceNotFoundError from ocp_resources.inference_service import InferenceService @@ -45,12 +47,20 @@ def __str__(self) -> str: return msg -def get_flan_pod(client: DynamicClient, namespace: str, name_prefix: str) -> Pod: - for pod in Pod.get(dyn_client=client, namespace=namespace): - if name_prefix + "-predictor" in pod.name: - return pod +def get_flan_deployment(client: DynamicClient, namespace: str, name_prefix: str) -> Deployment: + def _get_deployment( + dyn_client: DynamicClient = client, + namespace: str = namespace, + label_selector: str = f"serving.kserve.io/inferenceservice={name_prefix}", + ) -> Generator[Deployment, Any, Any]: + yield from Deployment.get(dyn_client=dyn_client, namespace=namespace, label_selector=label_selector) - raise ResourceNotFoundError(f"No flan predictor pod found in namespace {namespace}") + # There is supposed to be a single deployment for our resource, raise an exception otherwise + deployment = list(_get_deployment()) + if len(deployment) == 1: + return deployment[0] + else: + raise ResourceNotFoundError(f"flan predictor deployment not found in namespace {namespace}") def curl_from_pod( @@ -68,12 +78,13 @@ def curl_from_pod( return pod.execute(command=shlex.split(f"curl -k {host}/{endpoint}"), ignore_rc=True) +@contextmanager def create_sidecar_pod( admin_client: DynamicClient, namespace: str, istio: bool, pod_name: str, -) -> Pod: +) -> Generator[Pod, Any, Any]: cmd = f"oc run {pod_name} -n {namespace} --image=registry.access.redhat.com/rhel7/rhel-tools" if istio: cmd = f'{cmd} --annotations=sidecar.istio.io/inject="true"' @@ -82,16 +93,13 @@ def create_sidecar_pod( _, _, err = run_command(command=shlex.split(cmd), check=False) if err: - LOGGER.info(msg=err) - - containers = [pod_name] - if istio: - containers.append("istio-proxy") + LOGGER.error(msg=err) pod = Pod(name=pod_name, namespace=namespace, client=admin_client) pod.wait_for_status(status="Running") pod.wait_for_condition(condition="Ready", status="True") - return pod + yield pod + pod.clean_up() def b64_encoded_string(string_to_encode: str) -> str: @@ -107,6 +115,4 @@ def b64_encoded_string(string_to_encode: str) -> str: Returns: A base64 encoded string that is compliant with openshift's yaml format """ - # encodes the string to bytes-like, encodes the bytes-like to base 64, decodes the b64 to a string and returns it - # needed for openshift resources expecting b64 encoded values in the yaml return base64.b64encode(string_to_encode.encode()).decode() diff --git a/tests/model_serving/model_server/storage/pvc/conftest.py b/tests/model_serving/model_server/storage/pvc/conftest.py index 76d1c33..399cca0 100644 --- a/tests/model_serving/model_server/storage/pvc/conftest.py +++ b/tests/model_serving/model_server/storage/pvc/conftest.py @@ -1,7 +1,8 @@ import shlex -from typing import List, Optional, Tuple +from typing import List, Generator, Any import pytest +from pytest import FixtureRequest from kubernetes.dynamic import DynamicClient from kubernetes.dynamic.exceptions import ResourceNotFoundError from ocp_resources.deployment import Deployment @@ -10,79 +11,27 @@ from ocp_resources.persistent_volume_claim import PersistentVolumeClaim from ocp_resources.pod import Pod from ocp_resources.resource import ResourceEditor -from ocp_resources.service_mesh_member import ServiceMeshMember from ocp_resources.serving_runtime import ServingRuntime from ocp_resources.storage_class import StorageClass from ocp_utilities.infra import get_pods_by_name_prefix from tests.model_serving.model_server.storage.constants import NFS_STR from tests.model_serving.model_server.storage.pvc.utils import create_isvc +from tests.model_serving.constants import KSERVE_SERVERLESS from utilities.serving_runtime import ServingRuntimeFromTemplate -@pytest.fixture(scope="session") -def aws_access_key_id(pytestconfig) -> Optional[str]: - access_key = pytestconfig.option.aws_access_key_id - if not access_key: - raise ValueError( - "AWS access key id is not set. " - "Either pass with `--aws-access-key-id` or set `AWS_ACCESS_KEY_ID` environment variable" - ) - - return access_key - - -@pytest.fixture(scope="session") -def aws_secret_access_key(pytestconfig) -> Optional[str]: - secret_access_key = pytestconfig.option.aws_secret_access_key - if not secret_access_key: - raise ValueError( - "AWS secret access key is not set. " - "Either pass with `--aws-secret-access-key` or set `AWS_SECRET_ACCESS_KEY` environment variable" - ) - - return secret_access_key - - -@pytest.fixture(scope="session") -def valid_aws_config(aws_access_key_id: str, aws_secret_access_key: str) -> Tuple[str, str]: - return aws_access_key_id, aws_secret_access_key - - @pytest.fixture(scope="class") -def service_mesh_member(admin_client: DynamicClient, model_namespace: Namespace) -> ServiceMeshMember: - with ServiceMeshMember( - client=admin_client, - name="default", - namespace=model_namespace.name, - control_plane_ref={"name": "data-science-smcp", "namespace": "istio-system"}, - ) as smm: - yield smm - - -@pytest.fixture(scope="session") -def ci_s3_bucket_name(pytestconfig) -> str: - bucket_name = pytestconfig.option.ci_s3_bucket_name - if not bucket_name: - raise ValueError( - "CI S3 bucket name is not set. " - "Either pass with `--ci-s3-bucket-name` or set `CI_S3_BUCKET_NAME` environment variable" - ) - - return bucket_name - - -@pytest.fixture(scope="class") -def ci_s3_storage_uri(request, ci_s3_bucket_name) -> str: +def ci_s3_storage_uri(request: FixtureRequest, ci_s3_bucket_name: str) -> str: return f"s3://{ci_s3_bucket_name}/{request.param['model-dir']}/" @pytest.fixture(scope="class") def model_pvc( - request, + request: FixtureRequest, admin_client: DynamicClient, model_namespace: Namespace, -) -> PersistentVolumeClaim: +) -> Generator[PersistentVolumeClaim, Any, Any]: access_mode = "ReadWriteOnce" pvc_kwargs = { "name": "model-pvc", @@ -146,12 +95,11 @@ def downloaded_model_data( @pytest.fixture(scope="class") def serving_runtime( - request, + request: FixtureRequest, admin_client: DynamicClient, - service_mesh_member: ServiceMeshMember, model_namespace: Namespace, downloaded_model_data: str, -) -> ServingRuntime: +) -> Generator[ServingRuntime, Any, Any]: with ServingRuntimeFromTemplate( client=admin_client, name=request.param["name"], @@ -163,13 +111,13 @@ def serving_runtime( @pytest.fixture(scope="class") def inference_service( - request, + request: FixtureRequest, admin_client: DynamicClient, model_namespace: Namespace, serving_runtime: ServingRuntime, model_pvc: PersistentVolumeClaim, downloaded_model_data: str, -) -> InferenceService: +) -> Generator[InferenceService, Any, Any]: isvc_kwargs = { "client": admin_client, "name": request.param["name"], @@ -177,7 +125,7 @@ def inference_service( "runtime": serving_runtime.name, "storage_uri": f"pvc://{model_pvc.name}/{downloaded_model_data}", "model_format": serving_runtime.instance.spec.supportedModelFormats[0].name, - "deployment_mode": request.param.get("deployment-mode", "Serverless"), + "deployment_mode": request.param.get("deployment-mode", KSERVE_SERVERLESS), } if min_replicas := request.param.get("min-replicas"): @@ -227,12 +175,16 @@ def predictor_pods_scope_class( @pytest.fixture() -def first_predictor_pod(predictor_pods_scope_function) -> Pod: +def first_predictor_pod(predictor_pods_scope_function: List[Pod]) -> Pod: return predictor_pods_scope_function[0] @pytest.fixture() -def patched_isvc(request, inference_service: InferenceService, first_predictor_pod: Pod) -> InferenceService: +def patched_isvc( + request: FixtureRequest, + inference_service: InferenceService, + first_predictor_pod: Pod, +) -> Generator[InferenceService, Any, Any]: with ResourceEditor( patches={ inference_service: { @@ -247,6 +199,6 @@ def patched_isvc(request, inference_service: InferenceService, first_predictor_p @pytest.fixture(scope="module") -def skip_if_no_nfs_storage_class(admin_client): +def skip_if_no_nfs_storage_class(admin_client: DynamicClient) -> None: if not StorageClass(client=admin_client, name=NFS_STR).exists: pytest.skip(f"StorageClass {NFS_STR} is missing from the cluster") diff --git a/tests/model_serving/model_server/storage/pvc/test_kserve_pvc_rwx.py b/tests/model_serving/model_server/storage/pvc/test_kserve_pvc_rwx.py index 06540e3..d3f6f78 100644 --- a/tests/model_serving/model_server/storage/pvc/test_kserve_pvc_rwx.py +++ b/tests/model_serving/model_server/storage/pvc/test_kserve_pvc_rwx.py @@ -1,5 +1,6 @@ import shlex from typing import List +from tests.model_serving.constants import KSERVE_SERVERLESS import pytest @@ -24,7 +25,7 @@ {"model-dir": "test-dir"}, {"access-modes": "ReadWriteMany", "storage-class-name": NFS_STR}, KSERVE_OVMS_SERVING_RUNTIME_PARAMS, - INFERENCE_SERVICE_PARAMS | {"deployment-mode": "Serverless", "min-replicas": 2}, + INFERENCE_SERVICE_PARAMS | {"deployment-mode": KSERVE_SERVERLESS, "min-replicas": 2}, ) ], indirect=True, diff --git a/tests/model_serving/model_server/storage/pvc/utils.py b/tests/model_serving/model_server/storage/pvc/utils.py index 3ebc0fd..473644e 100644 --- a/tests/model_serving/model_server/storage/pvc/utils.py +++ b/tests/model_serving/model_server/storage/pvc/utils.py @@ -1,5 +1,5 @@ from contextlib import contextmanager -from typing import Optional, Generator, Any +from typing import Optional, Generator, Any, Dict from kubernetes.dynamic import DynamicClient from ocp_resources.inference_service import InferenceService @@ -20,7 +20,7 @@ def create_isvc( min_replicas: int = 1, wait: bool = True, ) -> Generator[InferenceService, Any, Any]: - predictor_dict = { + predictor_dict: Dict[str, Any] = { "minReplicas": min_replicas, "model": { "modelFormat": {"name": model_format}, @@ -28,13 +28,12 @@ def create_isvc( "runtime": runtime, }, } - # "type:ignore" is needed because otherwise mypy will complain about "Unsupported target for indexed assignment ("object")" if storage_uri and storage_key and storage_path: raise InvalidStorageArgument(storage_uri, storage_key, storage_path) elif storage_uri: - predictor_dict["model"]["storageUri"] = storage_uri # type: ignore + predictor_dict["model"]["storageUri"] = storage_uri elif storage_key and storage_path: - predictor_dict["model"]["storage"] = {"key": storage_key, "path": storage_path} # type: ignore + predictor_dict["model"]["storage"] = {"key": storage_key, "path": storage_path} else: raise InvalidStorageArgument(storage_uri, storage_key, storage_path) @@ -58,3 +57,12 @@ def create_isvc( timeout=10 * 60, ) yield inference_service + + +def check_storage_arguments( + storage_uri: str, + storage_key: str, + storage_path: str, +) -> None: + if (storage_uri and storage_path) or (not storage_uri and not storage_key) or (storage_key and not storage_path): + raise InvalidStorageArgument(storage_uri, storage_key, storage_path) diff --git a/tests/utils.py b/tests/utils.py index 43729de..53c1b36 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -1,5 +1,5 @@ from contextlib import contextmanager -from typing import Any, Dict, Optional +from typing import Any, Dict, Optional, Generator from kubernetes.dynamic import DynamicClient from ocp_resources.namespace import Namespace @@ -13,7 +13,7 @@ def create_ns( name: str, labels: Optional[Dict[str, Any]] = None, wait_for_resource: bool = True, -) -> Namespace: +) -> Generator[Namespace, Any, Any]: with Namespace( client=client, name=name, From fc93abf36d60e14226b2ca10326babd8935f2b83 Mon Sep 17 00:00:00 2001 From: lugi0 Date: Mon, 25 Nov 2024 16:30:59 +0100 Subject: [PATCH 26/31] add typing to storage_check func Signed-off-by: lugi0 --- .../model_server/private_endpoint/utils.py | 1 - .../model_server/storage/pvc/utils.py | 17 +++++++---------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/tests/model_serving/model_server/private_endpoint/utils.py b/tests/model_serving/model_server/private_endpoint/utils.py index e012cb6..02d1da1 100644 --- a/tests/model_serving/model_server/private_endpoint/utils.py +++ b/tests/model_serving/model_server/private_endpoint/utils.py @@ -96,7 +96,6 @@ def create_sidecar_pod( LOGGER.error(msg=err) pod = Pod(name=pod_name, namespace=namespace, client=admin_client) - pod.wait_for_status(status="Running") pod.wait_for_condition(condition="Ready", status="True") yield pod pod.clean_up() diff --git a/tests/model_serving/model_server/storage/pvc/utils.py b/tests/model_serving/model_server/storage/pvc/utils.py index 473644e..cb17b9b 100644 --- a/tests/model_serving/model_server/storage/pvc/utils.py +++ b/tests/model_serving/model_server/storage/pvc/utils.py @@ -28,14 +28,11 @@ def create_isvc( "runtime": runtime, }, } - if storage_uri and storage_key and storage_path: - raise InvalidStorageArgument(storage_uri, storage_key, storage_path) - elif storage_uri: + _check_storage_arguments(storage_uri, storage_key, storage_path) + if storage_uri: predictor_dict["model"]["storageUri"] = storage_uri - elif storage_key and storage_path: + elif storage_key: predictor_dict["model"]["storage"] = {"key": storage_key, "path": storage_path} - else: - raise InvalidStorageArgument(storage_uri, storage_key, storage_path) with InferenceService( client=client, @@ -59,10 +56,10 @@ def create_isvc( yield inference_service -def check_storage_arguments( - storage_uri: str, - storage_key: str, - storage_path: str, +def _check_storage_arguments( + storage_uri: Optional[str], + storage_key: Optional[str], + storage_path: Optional[str], ) -> None: if (storage_uri and storage_path) or (not storage_uri and not storage_key) or (storage_key and not storage_path): raise InvalidStorageArgument(storage_uri, storage_key, storage_path) From 471360f83e33f520a130ded7897afd1c9faa9bc6 Mon Sep 17 00:00:00 2001 From: lugi0 Date: Mon, 25 Nov 2024 17:06:01 +0100 Subject: [PATCH 27/31] update deployment readiness check Signed-off-by: lugi0 --- .../model_server/private_endpoint/conftest.py | 3 +- .../model_server/private_endpoint/utils.py | 30 +++++++++++-------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/tests/model_serving/model_server/private_endpoint/conftest.py b/tests/model_serving/model_server/private_endpoint/conftest.py index 277a709..9db05b1 100644 --- a/tests/model_serving/model_server/private_endpoint/conftest.py +++ b/tests/model_serving/model_server/private_endpoint/conftest.py @@ -182,9 +182,8 @@ def diff_pod_without_istio_sidecar( @pytest.fixture() def ready_predictor(admin_client: DynamicClient, endpoint_isvc: InferenceService) -> None: - predictor_deployment = get_flan_deployment( + get_flan_deployment( namespace=endpoint_isvc.namespace, client=admin_client, name_prefix=endpoint_isvc.name, ) - predictor_deployment.wait_for_replicas() diff --git a/tests/model_serving/model_server/private_endpoint/utils.py b/tests/model_serving/model_server/private_endpoint/utils.py index 02d1da1..59d0b18 100644 --- a/tests/model_serving/model_server/private_endpoint/utils.py +++ b/tests/model_serving/model_server/private_endpoint/utils.py @@ -7,7 +7,7 @@ from ocp_resources.pod import Pod from ocp_resources.deployment import Deployment from kubernetes.dynamic.client import DynamicClient -from kubernetes.dynamic.exceptions import ResourceNotFoundError +from kubernetes.dynamic.exceptions import ResourceNotFoundError, ResourceNotUniqueError from ocp_resources.inference_service import InferenceService from pyhelper_utils.shell import run_command from simple_logger.logger import get_logger @@ -48,19 +48,23 @@ def __str__(self) -> str: def get_flan_deployment(client: DynamicClient, namespace: str, name_prefix: str) -> Deployment: - def _get_deployment( - dyn_client: DynamicClient = client, - namespace: str = namespace, - label_selector: str = f"serving.kserve.io/inferenceservice={name_prefix}", - ) -> Generator[Deployment, Any, Any]: - yield from Deployment.get(dyn_client=dyn_client, namespace=namespace, label_selector=label_selector) - - # There is supposed to be a single deployment for our resource, raise an exception otherwise - deployment = list(_get_deployment()) - if len(deployment) == 1: - return deployment[0] + deployments = list( + Deployment.get( + label_selector=f"serving.kserve.io/inferenceservice={name_prefix}", + client=client, + namespace=namespace, + ) + ) + + if len(deployments) == 1: + deployment = deployments[0] + if deployment.exists: + deployment.wait_for_replicas() + return + elif len(deployments) > 1: + raise ResourceNotUniqueError(f"Multiple flan predictor deployments found in namespace {namespace}") else: - raise ResourceNotFoundError(f"flan predictor deployment not found in namespace {namespace}") + raise ResourceNotFoundError(f"Flan predictor deployment not found in namespace {namespace}") def curl_from_pod( From bb7b21c0e78aa262e2d261e2a69f76b106d76a2e Mon Sep 17 00:00:00 2001 From: lugi0 Date: Mon, 25 Nov 2024 17:45:02 +0100 Subject: [PATCH 28/31] Address PR comments Signed-off-by: lugi0 --- tests/conftest.py | 4 ++-- .../model_server/private_endpoint/conftest.py | 10 ++++---- .../model_server/private_endpoint/utils.py | 2 +- .../model_server/storage/pvc/conftest.py | 2 +- .../model_server/{storage/pvc => }/utils.py | 0 tests/trustyai/conftest.py | 8 ++++--- tests/utils.py | 23 ------------------- .../private_endpoint => utilities}/infra.py | 2 ++ 8 files changed, 17 insertions(+), 34 deletions(-) rename tests/model_serving/model_server/{storage/pvc => }/utils.py (100%) delete mode 100644 tests/utils.py rename {tests/model_serving/model_server/private_endpoint => utilities}/infra.py (91%) diff --git a/tests/conftest.py b/tests/conftest.py index 650bc1a..b6f4fb3 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -6,7 +6,7 @@ from ocp_resources.namespace import Namespace from ocp_resources.resource import get_client -from tests.utils import create_ns +from utilities.infra import create_ns @pytest.fixture(scope="session") @@ -16,7 +16,7 @@ def admin_client() -> DynamicClient: @pytest.fixture(scope="class") def model_namespace(request: FixtureRequest, admin_client: DynamicClient) -> Generator[Namespace, Any, Any]: - with create_ns(client=admin_client, name=request.param["name"]) as ns: + with create_ns(admin_client=admin_client, name=request.param["name"]) as ns: yield ns diff --git a/tests/model_serving/model_server/private_endpoint/conftest.py b/tests/model_serving/model_server/private_endpoint/conftest.py index 9db05b1..79b504a 100644 --- a/tests/model_serving/model_server/private_endpoint/conftest.py +++ b/tests/model_serving/model_server/private_endpoint/conftest.py @@ -10,13 +10,13 @@ from kubernetes.dynamic import DynamicClient from utilities.serving_runtime import ServingRuntimeFromTemplate -from tests.model_serving.model_server.storage.pvc.utils import create_isvc +from tests.model_serving.model_server.utils import create_isvc from tests.model_serving.model_server.private_endpoint.utils import ( create_sidecar_pod, get_flan_deployment, b64_encoded_string, ) -from tests.model_serving.model_server.private_endpoint.infra import create_ns +from utilities.infra import create_ns from tests.model_serving.constants import KSERVE_SERVERLESS @@ -25,12 +25,14 @@ @pytest.fixture(scope="session") def endpoint_namespace(admin_client: DynamicClient) -> Generator[Namespace, None, None]: - yield from create_ns(admin_client=admin_client, name="endpoint-namespace") + with create_ns(admin_client=admin_client, name="endpoint-namespace") as ns: + yield ns @pytest.fixture(scope="session") def diff_namespace(admin_client: DynamicClient) -> Generator[Namespace, None, None]: - yield from create_ns(admin_client=admin_client, name="diff-namespace") + with create_ns(admin_client=admin_client, name="diff-namespace") as ns: + yield ns @pytest.fixture(scope="session") diff --git a/tests/model_serving/model_server/private_endpoint/utils.py b/tests/model_serving/model_server/private_endpoint/utils.py index 59d0b18..ca6a84f 100644 --- a/tests/model_serving/model_server/private_endpoint/utils.py +++ b/tests/model_serving/model_server/private_endpoint/utils.py @@ -60,7 +60,7 @@ def get_flan_deployment(client: DynamicClient, namespace: str, name_prefix: str) deployment = deployments[0] if deployment.exists: deployment.wait_for_replicas() - return + return deployment elif len(deployments) > 1: raise ResourceNotUniqueError(f"Multiple flan predictor deployments found in namespace {namespace}") else: diff --git a/tests/model_serving/model_server/storage/pvc/conftest.py b/tests/model_serving/model_server/storage/pvc/conftest.py index 399cca0..becbe5b 100644 --- a/tests/model_serving/model_server/storage/pvc/conftest.py +++ b/tests/model_serving/model_server/storage/pvc/conftest.py @@ -16,7 +16,7 @@ from ocp_utilities.infra import get_pods_by_name_prefix from tests.model_serving.model_server.storage.constants import NFS_STR -from tests.model_serving.model_server.storage.pvc.utils import create_isvc +from tests.model_serving.model_server.utils import create_isvc from tests.model_serving.constants import KSERVE_SERVERLESS from utilities.serving_runtime import ServingRuntimeFromTemplate diff --git a/tests/model_serving/model_server/storage/pvc/utils.py b/tests/model_serving/model_server/utils.py similarity index 100% rename from tests/model_serving/model_server/storage/pvc/utils.py rename to tests/model_serving/model_server/utils.py diff --git a/tests/trustyai/conftest.py b/tests/trustyai/conftest.py index 9e69ed1..b781e54 100644 --- a/tests/trustyai/conftest.py +++ b/tests/trustyai/conftest.py @@ -2,6 +2,8 @@ import pytest import yaml +from pytest import FixtureRequest +from typing import Generator, Any from kubernetes.dynamic import DynamicClient from ocp_resources.config_map import ConfigMap from ocp_resources.deployment import Deployment @@ -14,7 +16,7 @@ from tests.trustyai.constants import TRUSTYAI_SERVICE, MODELMESH_SERVING from tests.trustyai.utils import update_configmap_data -from tests.utils import create_ns +from utilities.infra import create_ns MINIO: str = "minio" OPENDATAHUB_IO: str = "opendatahub.io" @@ -44,8 +46,8 @@ def trustyai_service_with_pvc_storage( @pytest.fixture(scope="class") -def ns_with_modelmesh_enabled(request, admin_client: DynamicClient): - with create_ns(client=admin_client, name=request.param["name"], labels={"modelmesh-enabled": "true"}) as ns: +def ns_with_modelmesh_enabled(request: FixtureRequest, admin_client: DynamicClient) -> Generator[Namespace, Any, Any]: + with create_ns(admin_client=admin_client, name=request.param["name"], labels={"modelmesh-enabled": "true"}) as ns: yield ns diff --git a/tests/utils.py b/tests/utils.py deleted file mode 100644 index 53c1b36..0000000 --- a/tests/utils.py +++ /dev/null @@ -1,23 +0,0 @@ -from contextlib import contextmanager -from typing import Any, Dict, Optional, Generator - -from kubernetes.dynamic import DynamicClient -from ocp_resources.namespace import Namespace - -TIMEOUT_2MIN = 2 * 60 - - -@contextmanager -def create_ns( - client: DynamicClient, - name: str, - labels: Optional[Dict[str, Any]] = None, - wait_for_resource: bool = True, -) -> Generator[Namespace, Any, Any]: - with Namespace( - client=client, - name=name, - label=labels, - wait_for_resource=wait_for_resource, - ) as ns: - yield ns diff --git a/tests/model_serving/model_server/private_endpoint/infra.py b/utilities/infra.py similarity index 91% rename from tests/model_serving/model_server/private_endpoint/infra.py rename to utilities/infra.py index 38b5d07..8ed0cd4 100644 --- a/tests/model_serving/model_server/private_endpoint/infra.py +++ b/utilities/infra.py @@ -1,9 +1,11 @@ from typing import Generator, Dict, Optional +from contextlib import contextmanager from kubernetes.dynamic import DynamicClient from ocp_resources.namespace import Namespace +@contextmanager def create_ns( name: str, admin_client: DynamicClient, From 174f4a5fd5b3021dcd7e67f902ff2a08142ac611 Mon Sep 17 00:00:00 2001 From: lugi0 Date: Tue, 26 Nov 2024 16:26:12 +0100 Subject: [PATCH 29/31] Address PR comments Signed-off-by: lugi0 --- tests/conftest.py | 8 ++--- tests/constants.py | 22 ++++++++++++++ tests/model_serving/constants.py | 2 -- .../model_server/private_endpoint/conftest.py | 20 ++++++------- .../test_kserve_private_endpoint.py | 29 +++++++++++-------- .../model_server/private_endpoint/utils.py | 10 +++---- .../model_server/storage/pvc/conftest.py | 4 +-- .../storage/pvc/test_kserve_pvc_rwx.py | 4 +-- 8 files changed, 62 insertions(+), 37 deletions(-) create mode 100644 tests/constants.py delete mode 100644 tests/model_serving/constants.py diff --git a/tests/conftest.py b/tests/conftest.py index b6f4fb3..7f0cc1a 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -63,7 +63,7 @@ def ci_s3_bucket_region(pytestconfig: pytest.Config) -> str: ci_bucket_region = pytestconfig.option.ci_s3_bucket_region if not ci_bucket_region: raise ValueError( - "Bucket name for the models bucket is not defined." + "Region for the ci s3 bucket is not defined." "Either pass with `--ci-s3-bucket-region` or set `CI_S3_BUCKET_REGION` environment variable" ) return ci_bucket_region @@ -74,7 +74,7 @@ def ci_s3_bucket_endpoint(pytestconfig: pytest.Config) -> str: ci_bucket_endpoint = pytestconfig.option.ci_s3_bucket_endpoint if not ci_bucket_endpoint: raise ValueError( - "Bucket name for the models bucket is not defined." + "Endpoint for the ci s3 bucket is not defined." "Either pass with `--ci-s3-bucket-endpoint` or set `CI_S3_BUCKET_ENDPOINT` environment variable" ) return ci_bucket_endpoint @@ -96,7 +96,7 @@ def models_s3_bucket_region(pytestconfig: pytest.Config) -> str: models_bucket_region = pytestconfig.option.models_s3_bucket_region if not models_bucket_region: raise ValueError( - "Bucket name for the models bucket is not defined." + "region for the models bucket is not defined." "Either pass with `--models-s3-bucket-region` or set `MODELS_S3_BUCKET_REGION` environment variable" ) return models_bucket_region @@ -107,7 +107,7 @@ def models_s3_bucket_endpoint(pytestconfig: pytest.Config) -> str: models_bucket_endpoint = pytestconfig.option.models_s3_bucket_endpoint if not models_bucket_endpoint: raise ValueError( - "Bucket name for the models bucket is not defined." + "endpoint for the models bucket is not defined." "Either pass with `--models-s3-bucket-endpoint` or set `MODELS_S3_BUCKET_ENDPOINT` environment variable" ) return models_bucket_endpoint diff --git a/tests/constants.py b/tests/constants.py new file mode 100644 index 0000000..90e6eb5 --- /dev/null +++ b/tests/constants.py @@ -0,0 +1,22 @@ +from enum import Enum + + +class KServeDeploymentType(Enum): + SERVERLESS: str = "Serverless" + RAW_DEPLOYMENT: str = "RawDeployment" + + +class ModelStoragePath(Enum): + FLAN_T5_SMALL: str = "flan-t5-small/flan-t5-small-caikit" + + +class ModelFormat(Enum): + CAIKIT: str = "caikit" + + +class CurlOutput(Enum): + HEALTH_OK: str = "OK" + + +class ModelEndpoint(Enum): + HEALTH: str = "health" diff --git a/tests/model_serving/constants.py b/tests/model_serving/constants.py deleted file mode 100644 index 2b07f37..0000000 --- a/tests/model_serving/constants.py +++ /dev/null @@ -1,2 +0,0 @@ -KSERVE_SERVERLESS: str = "Serverless" -KSERVE_RAWDEPLOYMENT: str = "RawDeployment" diff --git a/tests/model_serving/model_server/private_endpoint/conftest.py b/tests/model_serving/model_server/private_endpoint/conftest.py index 79b504a..c6cb1a2 100644 --- a/tests/model_serving/model_server/private_endpoint/conftest.py +++ b/tests/model_serving/model_server/private_endpoint/conftest.py @@ -13,11 +13,11 @@ from tests.model_serving.model_server.utils import create_isvc from tests.model_serving.model_server.private_endpoint.utils import ( create_sidecar_pod, - get_flan_deployment, + get_kserve_predictor_deployment, b64_encoded_string, ) from utilities.infra import create_ns -from tests.model_serving.constants import KSERVE_SERVERLESS +from tests.constants import KServeDeploymentType, ModelStoragePath, ModelFormat LOGGER = get_logger(name=__name__) @@ -88,10 +88,10 @@ def endpoint_isvc( client=admin_client, name="test", namespace=endpoint_namespace.name, - deployment_mode=KSERVE_SERVERLESS, + deployment_mode=KServeDeploymentType.SERVERLESS.value, storage_key="endpoint-s3-secret", - storage_path="flan-t5-small/flan-t5-small-caikit", - model_format="caikit", + storage_path=ModelStoragePath.FLAN_T5_SMALL.value, + model_format=ModelFormat.CAIKIT.value, runtime=endpoint_sr.name, ) as isvc: yield isvc @@ -135,7 +135,7 @@ def endpoint_pod_with_istio_sidecar( with create_sidecar_pod( admin_client=admin_client, namespace=endpoint_namespace.name, - istio=True, + use_istio=True, pod_name="test-with-istio", ) as pod: yield pod @@ -148,7 +148,7 @@ def endpoint_pod_without_istio_sidecar( with create_sidecar_pod( admin_client=admin_client, namespace=endpoint_namespace.name, - istio=False, + use_istio=False, pod_name="test", ) as pod: yield pod @@ -162,7 +162,7 @@ def diff_pod_with_istio_sidecar( with create_sidecar_pod( admin_client=admin_client, namespace=diff_namespace.name, - istio=True, + use_istio=True, pod_name="test-with-istio", ) as pod: yield pod @@ -176,7 +176,7 @@ def diff_pod_without_istio_sidecar( with create_sidecar_pod( admin_client=admin_client, namespace=diff_namespace.name, - istio=False, + use_istio=False, pod_name="test", ) as pod: yield pod @@ -184,7 +184,7 @@ def diff_pod_without_istio_sidecar( @pytest.fixture() def ready_predictor(admin_client: DynamicClient, endpoint_isvc: InferenceService) -> None: - get_flan_deployment( + get_kserve_predictor_deployment( namespace=endpoint_isvc.namespace, client=admin_client, name_prefix=endpoint_isvc.name, diff --git a/tests/model_serving/model_server/private_endpoint/test_kserve_private_endpoint.py b/tests/model_serving/model_server/private_endpoint/test_kserve_private_endpoint.py index 78fcfb6..c17f32f 100644 --- a/tests/model_serving/model_server/private_endpoint/test_kserve_private_endpoint.py +++ b/tests/model_serving/model_server/private_endpoint/test_kserve_private_endpoint.py @@ -6,20 +6,25 @@ from ocp_resources.pod import Pod from ocp_resources.deployment import Deployment from tests.model_serving.model_server.private_endpoint.utils import curl_from_pod +from tests.constants import CurlOutput, ModelEndpoint LOGGER = get_logger(name=__name__) class TestKserveInternalEndpoint: + "Tests the internal endpoint of a kserve predictor" + def test_deploy_model_state_loaded( self: Self, endpoint_namespace: Namespace, endpoint_isvc: InferenceService, ready_predictor: Deployment ) -> None: + "Verifies that the predictor gets to state Loaded" assert endpoint_isvc.instance.status.modelStatus.states.activeModelState == "Loaded" def test_deploy_model_url( self: Self, endpoint_namespace: Namespace, endpoint_isvc: InferenceService, ready_predictor: Deployment ) -> None: + "Verifies that the internal endpoint has the expected formatting" assert ( endpoint_isvc.instance.status.address.url == f"https://{endpoint_isvc.name}.{endpoint_namespace.name}.svc.cluster.local" @@ -30,56 +35,56 @@ def test_curl_with_istio_same_ns( endpoint_isvc: InferenceService, endpoint_pod_with_istio_sidecar: Pod, ) -> None: - LOGGER.info("Testing curl from the same namespace with a pod part of the service mesh") + "Verifies the response from the health endpoint, sending a request from a pod in the same ns and part of the Istio Service Mesh" curl_stdout = curl_from_pod( isvc=endpoint_isvc, pod=endpoint_pod_with_istio_sidecar, - endpoint="health", + endpoint=ModelEndpoint.HEALTH.value, ) - assert curl_stdout == "OK" + assert curl_stdout == CurlOutput.HEALTH_OK.value def test_curl_with_istio_diff_ns( self: Self, endpoint_isvc: InferenceService, diff_pod_with_istio_sidecar: Pod, ) -> None: - LOGGER.info("Testing curl from a different namespace with a pod part of the service mesh") + "Verifies the response from the health endpoint, sending a request from a pod in a different ns and part of the Istio Service Mesh" curl_stdout = curl_from_pod( isvc=endpoint_isvc, pod=diff_pod_with_istio_sidecar, - endpoint="health", + endpoint=ModelEndpoint.HEALTH.value, protocol="https", ) - assert curl_stdout == "OK" + assert curl_stdout == CurlOutput.HEALTH_OK.value def test_curl_outside_istio_same_ns( self: Self, endpoint_isvc: InferenceService, endpoint_pod_without_istio_sidecar: Pod, ) -> None: - LOGGER.info("Testing curl from the same namespace with a pod not part of the service mesh") + "Verifies the response from the health endpoint, sending a request from a pod in the same ns and not part of the Istio Service Mesh" curl_stdout = curl_from_pod( isvc=endpoint_isvc, pod=endpoint_pod_without_istio_sidecar, - endpoint="health", + endpoint=ModelEndpoint.HEALTH.value, protocol="https", ) - assert curl_stdout == "OK" + assert curl_stdout == CurlOutput.HEALTH_OK.value def test_curl_outside_istio_diff_ns( self: Self, endpoint_isvc: InferenceService, diff_pod_without_istio_sidecar: Pod, ) -> None: - LOGGER.info("Testing curl from a different namespace with a pod not part of the service mesh") + "Verifies the response from the health endpoint, sending a request from a pod in a different ns and not part of the Istio Service Mesh" curl_stdout = curl_from_pod( isvc=endpoint_isvc, pod=diff_pod_without_istio_sidecar, - endpoint="health", + endpoint=ModelEndpoint.HEALTH.value, protocol="https", ) - assert curl_stdout == "OK" + assert curl_stdout == CurlOutput.HEALTH_OK.value diff --git a/tests/model_serving/model_server/private_endpoint/utils.py b/tests/model_serving/model_server/private_endpoint/utils.py index ca6a84f..c6d573c 100644 --- a/tests/model_serving/model_server/private_endpoint/utils.py +++ b/tests/model_serving/model_server/private_endpoint/utils.py @@ -47,7 +47,7 @@ def __str__(self) -> str: return msg -def get_flan_deployment(client: DynamicClient, namespace: str, name_prefix: str) -> Deployment: +def get_kserve_predictor_deployment(client: DynamicClient, namespace: str, name_prefix: str) -> Deployment: deployments = list( Deployment.get( label_selector=f"serving.kserve.io/inferenceservice={name_prefix}", @@ -62,9 +62,9 @@ def get_flan_deployment(client: DynamicClient, namespace: str, name_prefix: str) deployment.wait_for_replicas() return deployment elif len(deployments) > 1: - raise ResourceNotUniqueError(f"Multiple flan predictor deployments found in namespace {namespace}") + raise ResourceNotUniqueError(f"Multiple predictor deployments found in namespace {namespace}") else: - raise ResourceNotFoundError(f"Flan predictor deployment not found in namespace {namespace}") + raise ResourceNotFoundError(f"Predictor deployment not found in namespace {namespace}") def curl_from_pod( @@ -86,11 +86,11 @@ def curl_from_pod( def create_sidecar_pod( admin_client: DynamicClient, namespace: str, - istio: bool, + use_istio: bool, pod_name: str, ) -> Generator[Pod, Any, Any]: cmd = f"oc run {pod_name} -n {namespace} --image=registry.access.redhat.com/rhel7/rhel-tools" - if istio: + if use_istio: cmd = f'{cmd} --annotations=sidecar.istio.io/inject="true"' cmd += " -- sleep infinity" diff --git a/tests/model_serving/model_server/storage/pvc/conftest.py b/tests/model_serving/model_server/storage/pvc/conftest.py index becbe5b..8578158 100644 --- a/tests/model_serving/model_server/storage/pvc/conftest.py +++ b/tests/model_serving/model_server/storage/pvc/conftest.py @@ -17,7 +17,7 @@ from tests.model_serving.model_server.storage.constants import NFS_STR from tests.model_serving.model_server.utils import create_isvc -from tests.model_serving.constants import KSERVE_SERVERLESS +from tests.constants import KServeDeploymentType from utilities.serving_runtime import ServingRuntimeFromTemplate @@ -125,7 +125,7 @@ def inference_service( "runtime": serving_runtime.name, "storage_uri": f"pvc://{model_pvc.name}/{downloaded_model_data}", "model_format": serving_runtime.instance.spec.supportedModelFormats[0].name, - "deployment_mode": request.param.get("deployment-mode", KSERVE_SERVERLESS), + "deployment_mode": request.param.get("deployment-mode", KServeDeploymentType.SERVERLESS.value), } if min_replicas := request.param.get("min-replicas"): diff --git a/tests/model_serving/model_server/storage/pvc/test_kserve_pvc_rwx.py b/tests/model_serving/model_server/storage/pvc/test_kserve_pvc_rwx.py index d3f6f78..38f522c 100644 --- a/tests/model_serving/model_server/storage/pvc/test_kserve_pvc_rwx.py +++ b/tests/model_serving/model_server/storage/pvc/test_kserve_pvc_rwx.py @@ -1,6 +1,6 @@ import shlex from typing import List -from tests.model_serving.constants import KSERVE_SERVERLESS +from tests.constants import KServeDeploymentType import pytest @@ -25,7 +25,7 @@ {"model-dir": "test-dir"}, {"access-modes": "ReadWriteMany", "storage-class-name": NFS_STR}, KSERVE_OVMS_SERVING_RUNTIME_PARAMS, - INFERENCE_SERVICE_PARAMS | {"deployment-mode": KSERVE_SERVERLESS, "min-replicas": 2}, + INFERENCE_SERVICE_PARAMS | {"deployment-mode": KServeDeploymentType.SERVERLESS.value, "min-replicas": 2}, ) ], indirect=True, From 841ef05ddf3fb0f85d7f5cb88c80a0132c42dfbe Mon Sep 17 00:00:00 2001 From: lugi0 Date: Tue, 26 Nov 2024 17:09:20 +0100 Subject: [PATCH 30/31] Address new comments Signed-off-by: lugi0 --- tests/constants.py | 22 ------------------ .../model_server/private_endpoint/conftest.py | 2 +- .../test_kserve_private_endpoint.py | 2 +- .../model_server/storage/pvc/conftest.py | 2 +- .../storage/pvc/test_kserve_pvc_rwx.py | 2 +- utilities/constants.py | 23 +++++++++++++++++++ 6 files changed, 27 insertions(+), 26 deletions(-) delete mode 100644 tests/constants.py diff --git a/tests/constants.py b/tests/constants.py deleted file mode 100644 index 90e6eb5..0000000 --- a/tests/constants.py +++ /dev/null @@ -1,22 +0,0 @@ -from enum import Enum - - -class KServeDeploymentType(Enum): - SERVERLESS: str = "Serverless" - RAW_DEPLOYMENT: str = "RawDeployment" - - -class ModelStoragePath(Enum): - FLAN_T5_SMALL: str = "flan-t5-small/flan-t5-small-caikit" - - -class ModelFormat(Enum): - CAIKIT: str = "caikit" - - -class CurlOutput(Enum): - HEALTH_OK: str = "OK" - - -class ModelEndpoint(Enum): - HEALTH: str = "health" diff --git a/tests/model_serving/model_server/private_endpoint/conftest.py b/tests/model_serving/model_server/private_endpoint/conftest.py index c6cb1a2..d2e2aa8 100644 --- a/tests/model_serving/model_server/private_endpoint/conftest.py +++ b/tests/model_serving/model_server/private_endpoint/conftest.py @@ -17,7 +17,7 @@ b64_encoded_string, ) from utilities.infra import create_ns -from tests.constants import KServeDeploymentType, ModelStoragePath, ModelFormat +from utilities.constants import KServeDeploymentType, ModelStoragePath, ModelFormat LOGGER = get_logger(name=__name__) diff --git a/tests/model_serving/model_server/private_endpoint/test_kserve_private_endpoint.py b/tests/model_serving/model_server/private_endpoint/test_kserve_private_endpoint.py index c17f32f..f524206 100644 --- a/tests/model_serving/model_server/private_endpoint/test_kserve_private_endpoint.py +++ b/tests/model_serving/model_server/private_endpoint/test_kserve_private_endpoint.py @@ -6,7 +6,7 @@ from ocp_resources.pod import Pod from ocp_resources.deployment import Deployment from tests.model_serving.model_server.private_endpoint.utils import curl_from_pod -from tests.constants import CurlOutput, ModelEndpoint +from utilities.constants import CurlOutput, ModelEndpoint LOGGER = get_logger(name=__name__) diff --git a/tests/model_serving/model_server/storage/pvc/conftest.py b/tests/model_serving/model_server/storage/pvc/conftest.py index 8578158..4c8d389 100644 --- a/tests/model_serving/model_server/storage/pvc/conftest.py +++ b/tests/model_serving/model_server/storage/pvc/conftest.py @@ -17,7 +17,7 @@ from tests.model_serving.model_server.storage.constants import NFS_STR from tests.model_serving.model_server.utils import create_isvc -from tests.constants import KServeDeploymentType +from utilities.constants import KServeDeploymentType from utilities.serving_runtime import ServingRuntimeFromTemplate diff --git a/tests/model_serving/model_server/storage/pvc/test_kserve_pvc_rwx.py b/tests/model_serving/model_server/storage/pvc/test_kserve_pvc_rwx.py index 38f522c..88ef524 100644 --- a/tests/model_serving/model_server/storage/pvc/test_kserve_pvc_rwx.py +++ b/tests/model_serving/model_server/storage/pvc/test_kserve_pvc_rwx.py @@ -1,6 +1,6 @@ import shlex from typing import List -from tests.constants import KServeDeploymentType +from utilities.constants import KServeDeploymentType import pytest diff --git a/utilities/constants.py b/utilities/constants.py index b2662e9..0fe1e49 100644 --- a/utilities/constants.py +++ b/utilities/constants.py @@ -1 +1,24 @@ +from enum import Enum + APPLICATIONS_NAMESPACE: str = "redhat-ods-applications" + + +class KServeDeploymentType(Enum): + SERVERLESS: str = "Serverless" + RAW_DEPLOYMENT: str = "RawDeployment" + + +class ModelFormat(Enum): + CAIKIT: str = "caikit" + + +class ModelStoragePath(Enum): + FLAN_T5_SMALL: str = f"flan-t5-small/flan-t5-small-{ModelFormat.CAIKIT.value}" + + +class CurlOutput(Enum): + HEALTH_OK: str = "OK" + + +class ModelEndpoint(Enum): + HEALTH: str = "health" From e713bcde348065f97ad9471c5fed130a02b80253 Mon Sep 17 00:00:00 2001 From: lugi0 Date: Wed, 27 Nov 2024 14:19:45 +0100 Subject: [PATCH 31/31] Remove Enum inheritance Signed-off-by: lugi0 --- .../model_server/private_endpoint/conftest.py | 6 +++--- .../test_kserve_private_endpoint.py | 16 ++++++++-------- .../model_server/storage/pvc/conftest.py | 2 +- .../storage/pvc/test_kserve_pvc_rwx.py | 2 +- utilities/constants.py | 14 ++++++-------- 5 files changed, 19 insertions(+), 21 deletions(-) diff --git a/tests/model_serving/model_server/private_endpoint/conftest.py b/tests/model_serving/model_server/private_endpoint/conftest.py index d2e2aa8..512002e 100644 --- a/tests/model_serving/model_server/private_endpoint/conftest.py +++ b/tests/model_serving/model_server/private_endpoint/conftest.py @@ -88,10 +88,10 @@ def endpoint_isvc( client=admin_client, name="test", namespace=endpoint_namespace.name, - deployment_mode=KServeDeploymentType.SERVERLESS.value, + deployment_mode=KServeDeploymentType.SERVERLESS, storage_key="endpoint-s3-secret", - storage_path=ModelStoragePath.FLAN_T5_SMALL.value, - model_format=ModelFormat.CAIKIT.value, + storage_path=ModelStoragePath.FLAN_T5_SMALL, + model_format=ModelFormat.CAIKIT, runtime=endpoint_sr.name, ) as isvc: yield isvc diff --git a/tests/model_serving/model_server/private_endpoint/test_kserve_private_endpoint.py b/tests/model_serving/model_server/private_endpoint/test_kserve_private_endpoint.py index f524206..f6e901b 100644 --- a/tests/model_serving/model_server/private_endpoint/test_kserve_private_endpoint.py +++ b/tests/model_serving/model_server/private_endpoint/test_kserve_private_endpoint.py @@ -40,9 +40,9 @@ def test_curl_with_istio_same_ns( curl_stdout = curl_from_pod( isvc=endpoint_isvc, pod=endpoint_pod_with_istio_sidecar, - endpoint=ModelEndpoint.HEALTH.value, + endpoint=ModelEndpoint.HEALTH, ) - assert curl_stdout == CurlOutput.HEALTH_OK.value + assert curl_stdout == CurlOutput.HEALTH_OK def test_curl_with_istio_diff_ns( self: Self, @@ -54,10 +54,10 @@ def test_curl_with_istio_diff_ns( curl_stdout = curl_from_pod( isvc=endpoint_isvc, pod=diff_pod_with_istio_sidecar, - endpoint=ModelEndpoint.HEALTH.value, + endpoint=ModelEndpoint.HEALTH, protocol="https", ) - assert curl_stdout == CurlOutput.HEALTH_OK.value + assert curl_stdout == CurlOutput.HEALTH_OK def test_curl_outside_istio_same_ns( self: Self, @@ -69,10 +69,10 @@ def test_curl_outside_istio_same_ns( curl_stdout = curl_from_pod( isvc=endpoint_isvc, pod=endpoint_pod_without_istio_sidecar, - endpoint=ModelEndpoint.HEALTH.value, + endpoint=ModelEndpoint.HEALTH, protocol="https", ) - assert curl_stdout == CurlOutput.HEALTH_OK.value + assert curl_stdout == CurlOutput.HEALTH_OK def test_curl_outside_istio_diff_ns( self: Self, @@ -84,7 +84,7 @@ def test_curl_outside_istio_diff_ns( curl_stdout = curl_from_pod( isvc=endpoint_isvc, pod=diff_pod_without_istio_sidecar, - endpoint=ModelEndpoint.HEALTH.value, + endpoint=ModelEndpoint.HEALTH, protocol="https", ) - assert curl_stdout == CurlOutput.HEALTH_OK.value + assert curl_stdout == CurlOutput.HEALTH_OK diff --git a/tests/model_serving/model_server/storage/pvc/conftest.py b/tests/model_serving/model_server/storage/pvc/conftest.py index 4c8d389..84acf68 100644 --- a/tests/model_serving/model_server/storage/pvc/conftest.py +++ b/tests/model_serving/model_server/storage/pvc/conftest.py @@ -125,7 +125,7 @@ def inference_service( "runtime": serving_runtime.name, "storage_uri": f"pvc://{model_pvc.name}/{downloaded_model_data}", "model_format": serving_runtime.instance.spec.supportedModelFormats[0].name, - "deployment_mode": request.param.get("deployment-mode", KServeDeploymentType.SERVERLESS.value), + "deployment_mode": request.param.get("deployment-mode", KServeDeploymentType.SERVERLESS), } if min_replicas := request.param.get("min-replicas"): diff --git a/tests/model_serving/model_server/storage/pvc/test_kserve_pvc_rwx.py b/tests/model_serving/model_server/storage/pvc/test_kserve_pvc_rwx.py index 88ef524..7c364bd 100644 --- a/tests/model_serving/model_server/storage/pvc/test_kserve_pvc_rwx.py +++ b/tests/model_serving/model_server/storage/pvc/test_kserve_pvc_rwx.py @@ -25,7 +25,7 @@ {"model-dir": "test-dir"}, {"access-modes": "ReadWriteMany", "storage-class-name": NFS_STR}, KSERVE_OVMS_SERVING_RUNTIME_PARAMS, - INFERENCE_SERVICE_PARAMS | {"deployment-mode": KServeDeploymentType.SERVERLESS.value, "min-replicas": 2}, + INFERENCE_SERVICE_PARAMS | {"deployment-mode": KServeDeploymentType.SERVERLESS, "min-replicas": 2}, ) ], indirect=True, diff --git a/utilities/constants.py b/utilities/constants.py index 0fe1e49..282f327 100644 --- a/utilities/constants.py +++ b/utilities/constants.py @@ -1,24 +1,22 @@ -from enum import Enum - APPLICATIONS_NAMESPACE: str = "redhat-ods-applications" -class KServeDeploymentType(Enum): +class KServeDeploymentType: SERVERLESS: str = "Serverless" RAW_DEPLOYMENT: str = "RawDeployment" -class ModelFormat(Enum): +class ModelFormat: CAIKIT: str = "caikit" -class ModelStoragePath(Enum): - FLAN_T5_SMALL: str = f"flan-t5-small/flan-t5-small-{ModelFormat.CAIKIT.value}" +class ModelStoragePath: + FLAN_T5_SMALL: str = f"flan-t5-small/flan-t5-small-{ModelFormat.CAIKIT}" -class CurlOutput(Enum): +class CurlOutput: HEALTH_OK: str = "OK" -class ModelEndpoint(Enum): +class ModelEndpoint: HEALTH: str = "health"