Skip to content

Commit b3e18b8

Browse files
authored
Merge branch 'main' into must-gather
2 parents ae1fcaa + fe65421 commit b3e18b8

13 files changed

Lines changed: 254 additions & 49 deletions

File tree

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ repos:
3535
- id: detect-secrets
3636

3737
- repo: https://github.com/astral-sh/ruff-pre-commit
38-
rev: v0.11.8
38+
rev: v0.11.9
3939
hooks:
4040
- id: ruff
4141
- id: ruff-format

tests/conftest.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from ocp_resources.pod import Pod
1515
from ocp_resources.secret import Secret
1616
from ocp_resources.service import Service
17+
from ocp_utilities.monitoring import Prometheus
1718
from pyhelper_utils.shell import run_command
1819
from pytest import FixtureRequest, Config
1920
from kubernetes.dynamic import DynamicClient
@@ -23,6 +24,7 @@
2324
from pytest_testconfig import config as py_config
2425
from simple_logger.logger import get_logger
2526

27+
from utilities.certificates_utils import create_ca_bundle_file
2628
from utilities.data_science_cluster_utils import update_components_in_dsc
2729
from utilities.exceptions import ClusterLoginError
2830
from utilities.infra import (
@@ -520,3 +522,15 @@ def cluster_sanity_scope_session(
520522
dsci_resource=dsci_resource,
521523
junitxml_property=junitxml_plugin,
522524
)
525+
526+
527+
@pytest.fixture(scope="session")
528+
def prometheus(admin_client: DynamicClient) -> Prometheus:
529+
return Prometheus(
530+
client=admin_client,
531+
resource_name="thanos-querier",
532+
verify_ssl=create_ca_bundle_file(
533+
client=admin_client, ca_type="openshift"
534+
), # TODO: Verify SSL with appropriate certs
535+
bearer_token=get_openshift_token(),
536+
)

tests/model_explainability/trustyai_service/drift/test_drift.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from functools import partial
2+
13
import pytest
24

35
from tests.model_explainability.trustyai_service.constants import DRIFT_BASE_DATA_PATH
@@ -11,6 +13,7 @@
1113
)
1214
from utilities.constants import MinIo
1315
from utilities.manifests.openvino import OPENVINO_KSERVE_INFERENCE_CONFIG
16+
from utilities.monitoring import validate_metrics_field, get_metric_label
1417

1518

1619
@pytest.mark.parametrize(
@@ -103,6 +106,21 @@ def test_drift_metric_schedule_meanshift(
103106
},
104107
)
105108

109+
def test_drift_metric_prometheus(
110+
self,
111+
admin_client,
112+
model_namespace,
113+
trustyai_service_with_pvc_storage,
114+
gaussian_credit_model,
115+
prometheus,
116+
):
117+
validate_metrics_field(
118+
prometheus=prometheus,
119+
metrics_query=f'trustyai_{TrustyAIServiceMetrics.Drift.MEANSHIFT}{{namespace="{model_namespace.name}"}}',
120+
expected_value=TrustyAIServiceMetrics.Drift.MEANSHIFT.upper(),
121+
field_getter=partial(get_metric_label, label_name="metricName"),
122+
)
123+
106124
def test_drift_metric_delete(
107125
self,
108126
admin_client,

tests/model_explainability/trustyai_service/fairness/test_fairness.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from functools import partial
12
from typing import Any
23

34
import pytest
@@ -13,6 +14,7 @@
1314
)
1415
from utilities.constants import MinIo
1516
from utilities.manifests.openvino import OPENVINO_KSERVE_INFERENCE_CONFIG
17+
from utilities.monitoring import validate_metrics_field, get_metric_label
1618

1719
BASE_DATA_PATH: str = "./tests/model_explainability/trustyai_service/fairness/model_data"
1820
IS_MALE_IDENTIFYING: str = "Is Male-Identifying?"
@@ -115,6 +117,21 @@ def test_fairness_metric_schedule_spd_with_pvc_storage(
115117
json_data=get_fairness_request_json_data(isvc=onnx_loan_model),
116118
)
117119

120+
def test_fairness_metric_prometheus(
121+
self,
122+
admin_client,
123+
model_namespace,
124+
trustyai_service_with_pvc_storage,
125+
onnx_loan_model,
126+
prometheus,
127+
):
128+
validate_metrics_field(
129+
prometheus=prometheus,
130+
metrics_query=f'trustyai_{TrustyAIServiceMetrics.Fairness.SPD}{{namespace="{model_namespace.name}"}}',
131+
expected_value=TrustyAIServiceMetrics.Fairness.SPD.upper(),
132+
field_getter=partial(get_metric_label, label_name="metricName"),
133+
)
134+
118135
def test_fairness_metric_delete_with_pvc_storage(
119136
self, admin_client, current_client_token, trustyai_service_with_pvc_storage, onnx_loan_model
120137
):

tests/model_serving/model_server/conftest.py

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
from ocp_resources.service_account import ServiceAccount
1414
from ocp_resources.serving_runtime import ServingRuntime
1515
from ocp_resources.storage_class import StorageClass
16-
from ocp_utilities.monitoring import Prometheus
1716
from pytest_testconfig import config as py_config
1817
from simple_logger.logger import get_logger
1918

@@ -32,7 +31,6 @@
3231
)
3332
from utilities.inference_utils import create_isvc
3433
from utilities.infra import (
35-
get_openshift_token,
3634
s3_endpoint_secret,
3735
update_configmap_data,
3836
)
@@ -394,16 +392,6 @@ def http_s3_tensorflow_model_mesh_inference_service(
394392
yield isvc
395393

396394

397-
@pytest.fixture(scope="session")
398-
def prometheus(admin_client: DynamicClient) -> Prometheus:
399-
return Prometheus(
400-
client=admin_client,
401-
resource_name="thanos-querier",
402-
verify_ssl=False,
403-
bearer_token=get_openshift_token(),
404-
)
405-
406-
407395
@pytest.fixture(scope="class")
408396
def user_workload_monitoring_config_map(
409397
admin_client: DynamicClient, cluster_monitoring_config: ConfigMap

tests/model_serving/model_server/inference_service_configuration/conftest.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,16 @@
44
from kubernetes.dynamic import DynamicClient
55
from ocp_resources.inference_service import InferenceService
66
from ocp_resources.pod import Pod
7+
from ocp_resources.namespace import Namespace
8+
from ocp_resources.serving_runtime import ServingRuntime
9+
from utilities.inference_utils import create_isvc
10+
from utilities.constants import KServeDeploymentType
11+
712

813
from tests.model_serving.model_server.inference_service_configuration.constants import (
914
ISVC_ENV_VARS,
15+
UPDATED_PULL_SECRET,
16+
ORIGINAL_PULL_SECRET,
1017
)
1118
from tests.model_serving.model_server.inference_service_configuration.utils import (
1219
update_inference_service,
@@ -65,3 +72,58 @@ def patched_isvc_replicas(
6572
wait_for_new_pods=request.param["wait-for-new-pods"],
6673
):
6774
yield ovms_kserve_inference_service
75+
76+
77+
@pytest.fixture(scope="class")
78+
def model_car_raw_inference_service_with_pull_secret(
79+
request: pytest.FixtureRequest,
80+
unprivileged_client: DynamicClient,
81+
unprivileged_model_namespace: Namespace,
82+
serving_runtime_from_template: ServingRuntime,
83+
) -> Generator[InferenceService, Any, Any]:
84+
with create_isvc(
85+
client=unprivileged_client,
86+
name="model-car-raw",
87+
namespace=unprivileged_model_namespace.name,
88+
runtime=serving_runtime_from_template.name,
89+
storage_uri=request.param["storage-uri"],
90+
model_format=serving_runtime_from_template.instance.spec.supportedModelFormats[0].name,
91+
deployment_mode=KServeDeploymentType.RAW_DEPLOYMENT,
92+
image_pull_secrets=[ORIGINAL_PULL_SECRET],
93+
wait_for_predictor_pods=False, # Until modelcar initContainer completed, other containers may have Error status
94+
) as isvc:
95+
yield isvc
96+
97+
98+
@pytest.fixture(scope="class")
99+
def updated_isvc_pull_secret(
100+
request: pytest.FixtureRequest,
101+
unprivileged_client: DynamicClient,
102+
model_car_raw_inference_service_with_pull_secret: InferenceService,
103+
) -> Generator[InferenceService, Any, Any]:
104+
with update_inference_service(
105+
client=unprivileged_client,
106+
isvc=model_car_raw_inference_service_with_pull_secret,
107+
isvc_updated_dict={"spec": {"predictor": {"imagePullSecrets": [{"name": UPDATED_PULL_SECRET}]}}},
108+
):
109+
yield model_car_raw_inference_service_with_pull_secret
110+
111+
112+
@pytest.fixture(scope="class")
113+
def updated_isvc_remove_pull_secret(
114+
request: pytest.FixtureRequest,
115+
unprivileged_client: DynamicClient,
116+
model_car_raw_inference_service_with_pull_secret: InferenceService,
117+
) -> Generator[InferenceService, Any, Any]:
118+
with update_inference_service(
119+
client=unprivileged_client,
120+
isvc=model_car_raw_inference_service_with_pull_secret,
121+
isvc_updated_dict={
122+
"spec": {
123+
"predictor": {
124+
"imagePullSecrets": None # Explicitly remove the field
125+
}
126+
}
127+
},
128+
):
129+
yield model_car_raw_inference_service_with_pull_secret

tests/model_serving/model_server/inference_service_configuration/constants.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,6 @@
1010
{"name": "TEST_ENV_VAR1", "value": "test_value1"},
1111
{"name": "TEST_ENV_VAR2", "value": "test_value2"},
1212
]
13+
14+
ORIGINAL_PULL_SECRET: str = "pull-secret-1" # pragma: allowlist-secret
15+
UPDATED_PULL_SECRET: str = "updated-pull-secret" # pragma: allowlist-secret
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import pytest
2+
3+
from tests.model_serving.model_server.inference_service_configuration.utils import verify_pull_secret
4+
from tests.model_serving.model_server.inference_service_configuration.constants import (
5+
ORIGINAL_PULL_SECRET,
6+
UPDATED_PULL_SECRET,
7+
)
8+
from utilities.constants import ModelFormat, ModelName, RuntimeTemplates
9+
10+
11+
@pytest.mark.parametrize(
12+
"unprivileged_model_namespace, serving_runtime_from_template, model_car_raw_inference_service_with_pull_secret",
13+
[
14+
pytest.param(
15+
{"name": f"{ModelFormat.OPENVINO}-model-car"},
16+
{
17+
"name": f"{ModelName.MNIST}-runtime",
18+
"template-name": RuntimeTemplates.OVMS_KSERVE,
19+
"multi-model": False,
20+
},
21+
{
22+
# Using mnist-8-1 model from OCI image
23+
"storage-uri": "oci://quay.io/mwaykole/test@sha256:8a3217bcfa2cc5fa3d07496cff8b234acdf2c9725dd307dc0a80401f55e1a11c" # noqa: E501
24+
},
25+
)
26+
],
27+
indirect=True,
28+
)
29+
class TestISVCPullSecretUpdate:
30+
@pytest.mark.smoke
31+
def test_initial_pull_secret_set(self, model_car_raw_inference_service_with_pull_secret):
32+
"""Ensure initial pull secret is correctly set in the pod"""
33+
verify_pull_secret(
34+
isvc=model_car_raw_inference_service_with_pull_secret, pull_secret=ORIGINAL_PULL_SECRET, secret_exists=True
35+
)
36+
37+
def test_update_pull_secret(self, updated_isvc_pull_secret):
38+
"""Update the pull secret and verify it is reflected in the new pod"""
39+
verify_pull_secret(isvc=updated_isvc_pull_secret, pull_secret=UPDATED_PULL_SECRET, secret_exists=True)
40+
41+
def test_remove_pull_secret(self, updated_isvc_remove_pull_secret):
42+
verify_pull_secret(isvc=updated_isvc_remove_pull_secret, pull_secret=UPDATED_PULL_SECRET, secret_exists=False)

tests/model_serving/model_server/inference_service_configuration/utils.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,3 +108,32 @@ def wait_for_new_running_inference_pods(
108108
except TimeoutError:
109109
LOGGER.error(f"Timeout waiting for pods {oring_pods_names} to be replaced")
110110
raise
111+
112+
113+
def verify_pull_secret(isvc: InferenceService, pull_secret: str, secret_exists: bool) -> None:
114+
"""
115+
Verify that the ImagePullSecret in the InferenceService pods match the expected values.
116+
117+
Args:
118+
isvc (InferenceService): InferenceService object.
119+
pull_secret (str): Pull secret to verify
120+
secret_exists (bool): False if the pull secret should not exist in the pod.
121+
122+
Raises:
123+
AssertionError: If the imagePullSecrets do not match the expected presence or name.
124+
"""
125+
pod = get_pods_by_isvc_label(
126+
client=isvc.client,
127+
isvc=isvc,
128+
)[0]
129+
image_pull_secrets = pod.instance.spec.imagePullSecrets or []
130+
131+
secrets = [s.name for s in image_pull_secrets]
132+
133+
if secret_exists:
134+
assert secrets, "Expected imagePullSecrets to exist, but none were found."
135+
assert pull_secret in secrets, f"Expected pull secret '{pull_secret}' not found in imagePullSecrets: {secrets}"
136+
else:
137+
assert pull_secret not in secrets, (
138+
f"Did not expect pull secret '{pull_secret}', but found in imagePullSecrets: {secrets}"
139+
)

tests/model_serving/model_server/metrics/test_model_metrics.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
)
1515
from utilities.inference_utils import Inference
1616
from utilities.manifests.caikit_tgis import CAIKIT_TGIS_INFERENCE_CONFIG
17-
from utilities.monitoring import get_metrics_value, validate_metrics_value
17+
from utilities.monitoring import get_metrics_value, validate_metrics_field
1818

1919
pytestmark = [
2020
pytest.mark.serverless,
@@ -57,7 +57,7 @@ def test_model_metrics_num_success_requests(self, s3_models_inference_service, p
5757
model_name=ModelFormat.CAIKIT,
5858
use_default_query=True,
5959
)
60-
validate_metrics_value(
60+
validate_metrics_field(
6161
prometheus=prometheus,
6262
metrics_query="tgi_request_success",
6363
expected_value="1",
@@ -78,7 +78,7 @@ def test_model_metrics_num_total_requests(self, s3_models_inference_service, pro
7878
iterations=total_runs,
7979
run_in_parallel=True,
8080
)
81-
validate_metrics_value(
81+
validate_metrics_field(
8282
prometheus=prometheus,
8383
metrics_query="tgi_request_count",
8484
expected_value=str(total_runs + 1),

0 commit comments

Comments
 (0)