Skip to content

Commit 7ba8260

Browse files
committed
feat: update EvalHub and MLflow to match generated classes from openshift-python-wrapper#2691
Update resource classes to match the upstream generated code: - EvalHub: add collections and otel fields, change providers type to list[Any] - MLflow: change from NamespacedResource to Resource (cluster-scoped), add all new spec fields, remove namespace param from fixture Signed-off-by: Shelton Cyril <sheltoncyril@gmail.com>
1 parent 744061f commit 7ba8260

3 files changed

Lines changed: 281 additions & 19 deletions

File tree

tests/model_explainability/evalhub/conftest.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,6 @@ def mlflow_instance(
106106
with MLflow(
107107
client=admin_client,
108108
name="mlflow",
109-
namespace=py_config["applications_namespace"],
110109
storage={
111110
"accessModes": ["ReadWriteOnce"],
112111
"resources": {"requests": {"storage": "10Gi"}},

utilities/resources/evalhub.py

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,27 +15,44 @@ class EvalHub(NamespacedResource):
1515

1616
def __init__(
1717
self,
18+
collections: list[Any] | None = None,
1819
database: dict[str, Any] | None = None,
1920
env: list[Any] | None = None,
20-
providers: list[str] | None = None,
21+
otel: dict[str, Any] | None = None,
22+
providers: list[Any] | None = None,
2123
replicas: int | None = None,
2224
**kwargs: Any,
2325
) -> None:
2426
r"""
2527
Args:
26-
database (dict[str, Any]): Database configuration for the eval-hub service
28+
collections (list[Any]): Collections is the list of OOTB collection names to mount into the
29+
deployment. Each name must match a collection-name label on a
30+
ConfigMap in the operator namespace.
31+
32+
database (dict[str, Any]): Database configuration for persistent storage. This field is required:
33+
the operator will not start the service without an explicit
34+
database configuration. Set type to "postgresql" with a secret
35+
reference, or "sqlite" for lightweight/development deployments.
2736
2837
env (list[Any]): Environment variables for the eval-hub container
2938
30-
providers (list[str]): List of evaluation providers to enable
39+
otel (dict[str, Any]): OpenTelemetry configuration for observability. When set, the operator
40+
includes OTEL settings in the generated config. When omitted, the
41+
service uses its defaults (OTEL disabled).
42+
43+
providers (list[Any]): Providers is the list of OOTB provider names to mount into the
44+
deployment. Each name must match a provider-name label on a
45+
ConfigMap in the operator namespace.
3146
3247
replicas (int): Number of replicas for the eval-hub deployment
3348
3449
"""
3550
super().__init__(**kwargs)
3651

52+
self.collections = collections
3753
self.database = database
3854
self.env = env
55+
self.otel = otel
3956
self.providers = providers
4057
self.replicas = replicas
4158

@@ -47,12 +64,18 @@ def to_dict(self) -> None:
4764
self.res["spec"] = {}
4865
_spec = self.res["spec"]
4966

67+
if self.collections is not None:
68+
_spec["collections"] = self.collections
69+
5070
if self.database is not None:
5171
_spec["database"] = self.database
5272

5373
if self.env is not None:
5474
_spec["env"] = self.env
5575

76+
if self.otel is not None:
77+
_spec["otel"] = self.otel
78+
5679
if self.providers is not None:
5780
_spec["providers"] = self.providers
5881

utilities/resources/mlflow.py

Lines changed: 255 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,288 @@
1+
# Generated using https://github.com/RedHatQE/openshift-python-wrapper/blob/main/scripts/resource/README.md
2+
3+
14
from typing import Any
25

3-
from ocp_resources.resource import NamespacedResource
6+
from ocp_resources.resource import Resource
47

58

6-
class MLflow(NamespacedResource):
7-
"""MLflow is the Schema for the mlflows API."""
9+
class MLflow(Resource):
10+
"""
11+
MLflow is the Schema for the mlflows API
12+
"""
813

914
api_group: str = "mlflow.opendatahub.io"
1015

1116
def __init__(
1217
self,
13-
storage: dict[str, Any] | None = None,
14-
backend_store_uri: str | None = None,
18+
affinity: dict[str, Any] | None = None,
1519
artifacts_destination: str | None = None,
16-
serve_artifacts: bool | None = None,
20+
backend_store_uri: str | None = None,
21+
backend_store_uri_from: dict[str, Any] | None = None,
22+
ca_bundle_config_map: dict[str, Any] | None = None,
23+
default_artifact_root: str | None = None,
24+
env: list[Any] | None = None,
25+
env_from: list[Any] | None = None,
26+
extra_allowed_origins: list[Any] | None = None,
1727
image: dict[str, Any] | None = None,
28+
network_policy_additional_egress_rules: list[Any] | None = None,
29+
node_selector: dict[str, Any] | None = None,
30+
pod_annotations: dict[str, Any] | None = None,
31+
pod_labels: dict[str, Any] | None = None,
32+
pod_security_context: dict[str, Any] | None = None,
33+
registry_store_uri: str | None = None,
34+
registry_store_uri_from: dict[str, Any] | None = None,
35+
replicas: int | None = None,
36+
resources: dict[str, Any] | None = None,
37+
security_context: dict[str, Any] | None = None,
38+
serve_artifacts: bool | None = None,
39+
service_account_name: str | None = None,
40+
storage: dict[str, Any] | None = None,
41+
tolerations: list[Any] | None = None,
42+
workers: int | None = None,
1843
**kwargs: Any,
1944
) -> None:
45+
r"""
46+
Args:
47+
affinity (dict[str, Any]): Affinity specifies the pod's scheduling constraints
48+
49+
artifacts_destination (str): ArtifactsDestination is the server-side destination for MLflow
50+
artifacts (models, plots, files). This setting only applies when
51+
ServeArtifacts is enabled. When ServeArtifacts is disabled, this
52+
field is ignored and clients access artifact storage directly.
53+
Supported schemes: file://, s3://, gs://, wasbs://, hdfs://, etc.
54+
Examples: - "file:///mlflow/artifacts" (requires Storage to be
55+
configured) - "s3://my-bucket/mlflow/artifacts" (no Storage
56+
needed) - "gs://my-bucket/mlflow/artifacts" (no Storage needed)
57+
If not specified when ServeArtifacts is enabled, defaults to
58+
"file:///mlflow/artifacts" For cloud storage authentication, use
59+
EnvFrom to inject credentials from secrets or configmaps. Example
60+
for S3: envFrom: - secretRef: name: aws-credentials #
61+
Contains AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY Example for GCS:
62+
envFrom: - secretRef: name: gcp-credentials # Contains
63+
GOOGLE_APPLICATION_CREDENTIALS path
64+
65+
backend_store_uri (str): BackendStoreURI is the URI for the MLflow backend store (metadata).
66+
Supported schemes: file://, sqlite://, mysql://, postgresql://,
67+
etc. Examples: - "sqlite:////mlflow/mlflow.db" (requires Storage
68+
to be configured) Note: For URIs containing credentials, prefer
69+
using BackendStoreURIFrom for security. This must be set
70+
explicitly unless BackendStoreURIFrom is provided.
71+
72+
backend_store_uri_from (dict[str, Any]): BackendStoreURIFrom is a reference to a secret containing
73+
the backend
74+
store URI. Use this instead of BackendStoreURI when the URI
75+
contains credentials. Mutually exclusive with BackendStoreURI -
76+
the API rejects specs that set both.
77+
78+
ca_bundle_config_map (dict[str, Any]): CABundleConfigMap specifies a ConfigMap containing a CA certificate
79+
bundle. The bundle will be mounted into the MLflow container and
80+
configured for use with TLS connections (e.g. PostgreSQL SSL, S3
81+
with custom certificates).
82+
83+
default_artifact_root (str): DefaultArtifactRoot is the default artifact root path for MLflow runs
84+
on the server. This is required when serveArtifacts is false.
85+
Supported schemes: file://, s3://, gs://, wasbs://, hdfs://, etc.
86+
Examples: - "s3://my-bucket/mlflow/artifacts" - "gs://my-
87+
bucket/mlflow/artifacts" - "file:///mlflow/artifacts"
88+
89+
env (list[Any]): Env is a list of environment variables to set in the MLflow container
90+
91+
env_from (list[Any]): EnvFrom is a list of sources to populate environment variables in the
92+
MLflow container
93+
94+
extra_allowed_origins (list[Any]): ExtraAllowedOrigins is a list of additional origins to allow for CORS
95+
requests. The operator preconfigures safe defaults including
96+
Kubernetes service names, the data science gateway domain, and
97+
localhost. Use this field to add additional origins beyond the
98+
defaults. Each entry should be a full origin
99+
(scheme://host[:port]), e.g. "https://my-app.example.com".
100+
101+
image (dict[str, Any]): Image specifies the MLflow container image. If not specified, use the
102+
default image via the MLFLOW_IMAGE environment variable in the
103+
operator.
104+
105+
network_policy_additional_egress_rules (list[Any]): NetworkPolicyAdditionalEgressRules specifies
106+
additional egress rules
107+
to append to the default NetworkPolicy. The default policy permits
108+
DNS (53), HTTPS (443), Kubernetes API (6443), PostgreSQL (5432),
109+
MySQL (3306), and S3-compatible storage (MinIO 9000, SeaweedFS
110+
8333). Use this field when connecting to services on non-standard
111+
ports or when destination restrictions are needed.
112+
113+
node_selector (dict[str, Any]): NodeSelector is a selector which must be true for the pod to fit on a
114+
node
115+
116+
pod_annotations (dict[str, Any]): PodAnnotations are annotations to add only to the MLflow pod, not to
117+
other resources. Use this for pod-specific annotations like
118+
Prometheus scraping or sidecar configuration.
119+
120+
pod_labels (dict[str, Any]): PodLabels are labels to add only to the MLflow pod, not to other
121+
resources. Use this for pod-specific labels like version,
122+
component-specific metadata, etc. For labels that should be
123+
applied to all resources (Service, Deployment, etc.), use
124+
commonLabels in values.yaml.
125+
126+
pod_security_context (dict[str, Any]): PodSecurityContext specifies the security context for the MLflow pod
127+
128+
registry_store_uri (str): RegistryStoreURI is the URI for the MLflow registry store (model
129+
registry metadata). Supported schemes: file://, sqlite://,
130+
mysql://, postgresql://, etc. Examples: -
131+
"sqlite:////mlflow/mlflow.db" (requires Storage to be configured)
132+
If omitted, defaults to the same value as backendStoreUri. Note:
133+
For URIs containing credentials, prefer using RegistryStoreURIFrom
134+
for security.
135+
136+
registry_store_uri_from (dict[str, Any]): RegistryStoreURIFrom is a reference to a secret containing the
137+
registry store URI. Use this instead of RegistryStoreURI when the
138+
URI contains credentials. Mutually exclusive with RegistryStoreURI
139+
- the API rejects specs that set both.
140+
141+
replicas (int): Replicas is the number of MLflow pods to run
142+
143+
resources (dict[str, Any]): Resources specifies the compute resources for the MLflow container
144+
145+
security_context (dict[str, Any]): SecurityContext specifies the security context for the MLflow
146+
container
147+
148+
serve_artifacts (bool): ServeArtifacts determines whether MLflow should serve artifacts. When
149+
enabled, adds the --serve-artifacts flag to the MLflow server and
150+
uses ArtifactsDestination to configure where artifacts are stored.
151+
This allows clients to log and retrieve artifacts through the
152+
MLflow server's REST API instead of directly accessing the
153+
artifact storage. When disabled, ArtifactsDestination is ignored
154+
and clients must have direct access to artifact storage.
155+
156+
service_account_name (str): ServiceAccountName is the name of the ServiceAccount to use for the
157+
MLflow pod. If not specified, a default ServiceAccount will be
158+
"mlflow-sa"
159+
160+
storage (dict[str, Any]): Storage specifies the persistent storage configuration using standard
161+
PVC spec. Only required if using SQLite backend/registry stores or
162+
file-based artifacts. Not needed when using remote storage (S3,
163+
PostgreSQL, etc.). When omitted, no PVC will be created - ensure
164+
backendStoreUri, registryStoreUri, and artifactsDestination point
165+
to remote storage. Example: storage: accessModes:
166+
["ReadWriteOnce"] resources: requests: storage:
167+
10Gi storageClassName: fast-ssd
168+
169+
tolerations (list[Any]): Tolerations are the pod's tolerations
170+
171+
workers (int): Workers is the number of uvicorn worker processes for the MLflow
172+
server. Note: This is different from pod replicas. Each pod will
173+
run this many worker processes. Defaults to 1. For high-traffic
174+
deployments, consider increasing pod replicas instead.
175+
176+
"""
20177
super().__init__(**kwargs)
21178

22-
self.storage = storage
23-
self.backend_store_uri = backend_store_uri
179+
self.affinity = affinity
24180
self.artifacts_destination = artifacts_destination
25-
self.serve_artifacts = serve_artifacts
181+
self.backend_store_uri = backend_store_uri
182+
self.backend_store_uri_from = backend_store_uri_from
183+
self.ca_bundle_config_map = ca_bundle_config_map
184+
self.default_artifact_root = default_artifact_root
185+
self.env = env
186+
self.env_from = env_from
187+
self.extra_allowed_origins = extra_allowed_origins
26188
self.image = image
189+
self.network_policy_additional_egress_rules = network_policy_additional_egress_rules
190+
self.node_selector = node_selector
191+
self.pod_annotations = pod_annotations
192+
self.pod_labels = pod_labels
193+
self.pod_security_context = pod_security_context
194+
self.registry_store_uri = registry_store_uri
195+
self.registry_store_uri_from = registry_store_uri_from
196+
self.replicas = replicas
197+
self.resources = resources
198+
self.security_context = security_context
199+
self.serve_artifacts = serve_artifacts
200+
self.service_account_name = service_account_name
201+
self.storage = storage
202+
self.tolerations = tolerations
203+
self.workers = workers
27204

28205
def to_dict(self) -> None:
206+
29207
super().to_dict()
30208

31209
if not self.kind_dict and not self.yaml_file:
32210
self.res["spec"] = {}
33211
_spec = self.res["spec"]
34212

35-
if self.storage is not None:
36-
_spec["storage"] = self.storage
213+
if self.affinity is not None:
214+
_spec["affinity"] = self.affinity
215+
216+
if self.artifacts_destination is not None:
217+
_spec["artifactsDestination"] = self.artifacts_destination
37218

38219
if self.backend_store_uri is not None:
39220
_spec["backendStoreUri"] = self.backend_store_uri
40221

41-
if self.artifacts_destination is not None:
42-
_spec["artifactsDestination"] = self.artifacts_destination
222+
if self.backend_store_uri_from is not None:
223+
_spec["backendStoreUriFrom"] = self.backend_store_uri_from
43224

44-
if self.serve_artifacts is not None:
45-
_spec["serveArtifacts"] = self.serve_artifacts
225+
if self.ca_bundle_config_map is not None:
226+
_spec["caBundleConfigMap"] = self.ca_bundle_config_map
227+
228+
if self.default_artifact_root is not None:
229+
_spec["defaultArtifactRoot"] = self.default_artifact_root
230+
231+
if self.env is not None:
232+
_spec["env"] = self.env
233+
234+
if self.env_from is not None:
235+
_spec["envFrom"] = self.env_from
236+
237+
if self.extra_allowed_origins is not None:
238+
_spec["extraAllowedOrigins"] = self.extra_allowed_origins
46239

47240
if self.image is not None:
48241
_spec["image"] = self.image
242+
243+
if self.network_policy_additional_egress_rules is not None:
244+
_spec["networkPolicyAdditionalEgressRules"] = self.network_policy_additional_egress_rules
245+
246+
if self.node_selector is not None:
247+
_spec["nodeSelector"] = self.node_selector
248+
249+
if self.pod_annotations is not None:
250+
_spec["podAnnotations"] = self.pod_annotations
251+
252+
if self.pod_labels is not None:
253+
_spec["podLabels"] = self.pod_labels
254+
255+
if self.pod_security_context is not None:
256+
_spec["podSecurityContext"] = self.pod_security_context
257+
258+
if self.registry_store_uri is not None:
259+
_spec["registryStoreUri"] = self.registry_store_uri
260+
261+
if self.registry_store_uri_from is not None:
262+
_spec["registryStoreUriFrom"] = self.registry_store_uri_from
263+
264+
if self.replicas is not None:
265+
_spec["replicas"] = self.replicas
266+
267+
if self.resources is not None:
268+
_spec["resources"] = self.resources
269+
270+
if self.security_context is not None:
271+
_spec["securityContext"] = self.security_context
272+
273+
if self.serve_artifacts is not None:
274+
_spec["serveArtifacts"] = self.serve_artifacts
275+
276+
if self.service_account_name is not None:
277+
_spec["serviceAccountName"] = self.service_account_name
278+
279+
if self.storage is not None:
280+
_spec["storage"] = self.storage
281+
282+
if self.tolerations is not None:
283+
_spec["tolerations"] = self.tolerations
284+
285+
if self.workers is not None:
286+
_spec["workers"] = self.workers
287+
288+
# End of generated code

0 commit comments

Comments
 (0)