--- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.21.0 creationTimestamp: "2026-10-30T18:07:22Z" generation: 1 managedFields: - apiVersion: apiextensions.k8s.io/v1 fieldsType: FieldsV1 fieldsV1: f:metadata: f:annotations: .: {} f:controller-gen.kubebuilder.io/version: {} f:spec: f:conversion: .: {} f:strategy: {} f:group: {} f:names: f:kind: {} f:listKind: {} f:plural: {} f:singular: {} f:scope: {} f:versions: {} manager: helm operation: Update time: "2026-10-30T18:07:22Z" - apiVersion: apiextensions.k8s.io/v1 fieldsType: FieldsV1 fieldsV1: f:status: f:acceptedNames: f:kind: {} f:listKind: {} f:plural: {} f:singular: {} f:conditions: k:{"type":"Established"}: .: {} f:lastTransitionTime: {} f:message: {} f:reason: {} f:status: {} f:type: {} k:{"type":"NamesAccepted"}: .: {} f:lastTransitionTime: {} f:message: {} f:reason: {} f:status: {} f:type: {} manager: kube-apiserver operation: Update subresource: status time: "2026-10-30T18:07:22Z" name: monitorings.services.platform.opendatahub.io resourceVersion: "11511" uid: f7778faa-5184-48ee-96e4-841bd6753f0e spec: conversion: strategy: None group: services.platform.opendatahub.io names: kind: Monitoring listKind: MonitoringList plural: monitorings singular: monitoring scope: Cluster versions: - additionalPrinterColumns: - description: Ready jsonPath: .status.conditions[?(@.type=="Ready")].status name: Ready type: string - description: Reason jsonPath: .status.conditions[?(@.type=="Ready")].reason name: Reason type: string - description: URL jsonPath: .status.url name: URL type: string name: v1alpha1 schema: openAPIV3Schema: description: Monitoring is the Schema for the monitorings API. properties: apiVersion: description: |- APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: description: |- Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object spec: description: MonitoringSpec defines the desired state of Monitoring. properties: alerting: description: Alerting configures Prometheus alerting rules. type: object collectorReplicas: description: |- CollectorReplicas specifies the number of replicas in the OpenTelemetry collector. Defaults to 1 on single-node clusters and 2 on multi-node clusters. format: int32 minimum: 0 type: integer logs: description: Logs configures cluster log forwarding via the ClusterLogForwarder operator. properties: inferenceNamespaces: description: InferenceNamespaces lists the namespaces whose application logs should be forwarded to Loki. items: maxLength: 63 pattern: ^[a-z0-9]([a-z0-9\-]{0,61}[a-z0-9])?$ type: string type: array size: default: 1x.extra-small description: |- Size selects the log-forwarding LokiStack size. The default is 1x.extra-small; 1x.demo uses fewer resources but does not provide redundancy. enum: - 1x.demo - 1x.pico - 1x.extra-small - 1x.small - 1x.medium type: string storage: description: |- Storage configures the LokiStack storage backend for log forwarding. Required: the operator deploys a LokiStack dedicated to log forwarding, separate from the one usageLogs.storage deploys. The two stacks must use different object storage buckets. Both serve the "application" tenant and Loki keys objects by tenant rather than by stack, so a shared bucket makes them overwrite each other's index and chunks. Separate secrets are not sufficient; the operator compares the resolved endpoint and bucketnames and refuses to reconcile when they overlap. properties: credentialMode: default: static description: |- CredentialMode specifies how credentials are provided to LokiStack. Valid values: "static", "token", "token-cco". enum: - static - token - token-cco type: string secretName: description: |- SecretName is the name of the Secret containing storage credentials. For S3: must contain keys: access_key_id, access_key_secret, bucketnames, endpoint, region, insecure, s3ForcePathStyle maxLength: 253 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ type: string storageClassName: default: gp3-csi description: StorageClassName specifies the storage class for LokiStack PVCs. maxLength: 253 type: string type: description: 'Type specifies the storage backend: "s3".' enum: - s3 type: string required: - secretName - type type: object required: - storage type: object managementState: default: Managed description: |- ManagementState controls whether the operator actively manages the component (Managed) or removes it (Removed). enum: - Managed - Removed type: string metrics: description: Metrics configures metrics collection via the MonitoringStack operator. properties: builtinDCGMScrapeEnabled: description: |- BuiltinDCGMScrapeEnabled controls the built-in HTTP scrape for DCGM exporter metrics. It defaults to enabled; set false when collecting DCGM through a ServiceMonitor or PodMonitor instead. type: boolean exporters: additionalProperties: type: object x-kubernetes-preserve-unknown-fields: true description: |- Exporters defines custom metrics exporters for external observability tools. The configuration follows the OpenTelemetry Collector exporter format. Reserved names 'prometheus' and 'otlp/tempo' cannot be used. Maximum 10 exporters allowed. type: object x-kubernetes-validations: - message: exporter name 'prometheus' is reserved and cannot be used rule: '!(''prometheus'' in self)' - message: exporter name 'otlp/tempo' is reserved and cannot be used rule: '!(''otlp/tempo'' in self)' - message: maximum 10 exporters allowed rule: size(self) <= 10 replicas: description: Replicas specifies the number of replicas in the MonitoringStack. format: int32 minimum: 0 type: integer storage: description: Storage configures the built-in MonitoringStack backend. Omit when using exporters only (external observability). properties: retention: description: Retention specifies how long metrics data is retained (e.g. "1d", "2w"). type: string size: anyOf: - type: integer - type: string description: Size specifies the PVC storage size (e.g. "5Gi", "10Mi"). pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true type: object type: object x-kubernetes-validations: - message: metrics requires storage and/or at least one exporter rule: has(self.storage) || (has(self.exporters) && size(self.exporters) > 0) - message: Non-zero replicas require metrics.storage to be configured rule: has(self.storage) || !has(self.replicas) || self.replicas == 0 namespace: default: opendatahub description: Namespace is the target namespace where monitoring resources are deployed. maxLength: 63 pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?)?$ type: string x-kubernetes-validations: - message: Namespace is immutable rule: self == oldSelf traces: description: Traces configures distributed tracing via the Tempo operator. properties: exporters: additionalProperties: type: object x-kubernetes-preserve-unknown-fields: true description: Exporters defines custom trace exporters for external observability tools. type: object sampleRatio: description: SampleRatio determines the sampling rate for traces (0.0–1.0). pattern: ^(0(\.[0-9]+)?|1(\.0+)?)$ type: string storage: description: Storage configures the built-in Tempo backend. Omit when using exporters only (external observability). properties: backend: description: 'Backend defines the storage type: "pv", "s3", or "gcs".' enum: - pv - s3 - gcs type: string retention: description: Retention specifies how long trace data is retained (e.g. "60m", "10h"). type: string secret: description: Secret is the name of the Secret with storage credentials (non-PV backends). type: string size: description: Size specifies storage size (PV backend only). type: string required: - backend type: object x-kubernetes-validations: - message: When backend is s3 or gcs, the 'secret' field must be specified and non-empty rule: 'self.backend != ''pv'' ? (has(self.secret) && self.secret != "") : true' - message: Size is supported when backend is pv only rule: 'self.backend != ''pv'' ? !has(self.size) : true' tls: description: TLS configures TLS for Tempo gRPC connections. properties: caConfigMap: description: CAConfigMap is the name of the ConfigMap containing the CA certificate. type: string certificateSecret: description: CertificateSecret is the name of the Secret containing TLS certificates. type: string enabled: description: Enabled enables TLS for Tempo OTLP ingestion (gRPC/HTTP) and query APIs. type: boolean type: object type: object x-kubernetes-validations: - message: traces requires storage and/or at least one exporter rule: has(self.storage) || (has(self.exporters) && size(self.exporters) > 0) usageLogs: description: UsageLogs configures usage log collection and forwarding to Loki. properties: attributes: additionalProperties: type: string description: |- Attributes are resource attributes stamped onto records sent to Exporters only. They never reach the local write, so a cluster identity added here cannot disturb the spoke-local pipeline or its dashboards. Set cluster_name and cluster_id here to attribute records to the cluster that produced them; the gateway already uses cluster_name for its own upstream cluster, so these are applied after the pipeline's cleanup stage rather than merged into it. maxProperties: 20 type: object credentialSecret: description: |- CredentialSecret names a Secret in the monitoring namespace holding a bearer token under the key 'token', for authenticating to the Exporters' endpoint. It is mounted as a file and read through a bearertokenauth extension named 'bearertokenauth/remote', which an exporter selects with auth: {authenticator: bearertokenauth/remote}. The token is never written into the collector object, and because the extension re-reads the file, rotating the Secret reaches a running collector — projecting a credential as an environment variable would not, since env vars are read once at process start. A token also cannot be inlined into an exporter's headers: exporter values are capped at 1024 characters and a ServiceAccount token is longer than that. maxLength: 253 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ type: string exporters: additionalProperties: type: object x-kubernetes-preserve-unknown-fields: true description: |- Exporters defines additional usage-log exporters, for forwarding a copy of every usage record to an observability backend outside this cluster — typically a LokiStack on an ACM hub that aggregates a fleet. The configuration follows the OpenTelemetry Collector exporter format. They are added alongside the local write, which is left untouched, making it a dual-write rather than a redirect; with storage omitted they are the only destination and nothing is written locally. Reserved name 'otlphttp/loki' cannot be used. Maximum 10 exporters allowed. type: object x-kubernetes-validations: - message: exporter name 'otlphttp/loki' is reserved and cannot be used rule: '!(''otlphttp/loki'' in self)' - message: maximum 10 exporters allowed rule: size(self) <= 10 size: default: 1x.extra-small description: |- Size selects the LokiStack t-shirt size for the usage-log store. The default 1x.extra-small requests 1 CPU and 5.25Gi per ingester across three ingesters, which does not schedule on smaller clusters; the LokiStack then never reports Ready and the usage-logs collector is never deployed. 1x.demo carries identical ingestion limits with a single ingester and no resource requests at all, so it fits where the default cannot, but it has no redundancy. Ignored when storage is omitted, since no LokiStack is deployed. enum: - 1x.demo - 1x.pico - 1x.extra-small - 1x.small - 1x.medium type: string storage: description: |- Storage configures the LokiStack storage backend (S3). When configured, the operator deploys a LokiStack instance and auto-configures the collector endpoint. This stack is separate from the one logs.storage deploys and must use a different object storage bucket; see logs.storage for why a shared bucket is rejected. Omit when forwarding only: no LokiStack is deployed and no object storage is needed. properties: credentialMode: default: static description: |- CredentialMode specifies how credentials are provided to LokiStack. Valid values: "static", "token", "token-cco". enum: - static - token - token-cco type: string secretName: description: |- SecretName is the name of the Secret containing storage credentials. For S3: must contain keys: access_key_id, access_key_secret, bucketnames, endpoint, region, insecure, s3ForcePathStyle maxLength: 253 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ type: string storageClassName: default: gp3-csi description: StorageClassName specifies the storage class for LokiStack PVCs. maxLength: 253 type: string type: description: 'Type specifies the storage backend: "s3".' enum: - s3 type: string required: - secretName - type type: object type: object x-kubernetes-validations: - message: usageLogs requires storage and/or at least one exporter rule: has(self.storage) || (has(self.exporters) && size(self.exporters) > 0) type: object x-kubernetes-validations: - message: Alerting configuration requires metrics.storage to be configured rule: 'has(self.alerting) ? (has(self.metrics) && has(self.metrics.storage)) : true' - message: CollectorReplicas can only be set when metrics (storage or exporters) or traces are configured, and must be > 0 rule: '!has(self.collectorReplicas) || (self.collectorReplicas > 0 && ((has(self.metrics) && (has(self.metrics.storage) || (has(self.metrics.exporters) && size(self.metrics.exporters) > 0))) || has(self.traces)))' - message: Log forwarding requires logs.storage to be configured for the LokiStack instance rule: 'has(self.logs) ? has(self.logs.storage) : true' status: description: MonitoringStatus defines the observed state of Monitoring. properties: conditions: description: Conditions is the set of condition observations for this module. items: description: |- Condition represents an observation of a module's state at a point in time. Module controllers set conditions to communicate health signals to the orchestrator and to human operators. properties: lastHeartbeatTime: description: |- Deprecated: LastHeartbeatTime is present only for backward compatibility with existing CRDs. New code should not set this field. format: date-time type: string lastTransitionTime: description: |- lastTransitionTime is the last time the condition transitioned from one status to another. format: date-time type: string message: description: |- message is a human-readable message indicating details about the transition. type: string observedGeneration: description: |- observedGeneration represents the .metadata.generation that the condition was set based upon. If this does not match the resource's current generation, the condition is likely stale. format: int64 minimum: 0 type: integer reason: description: |- reason contains a programmatic identifier indicating the reason for the condition's last transition. The value should be a CamelCase string. type: string severity: description: |- Severity indicates whether this condition represents an error or is purely informational. Empty string (default) indicates error severity. type: string status: description: status of the condition, one of True, False, Unknown. enum: - "True" - "False" - Unknown type: string type: description: type of condition in CamelCase or in foo.example.com/CamelCase. maxLength: 316 pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string required: - status - type type: object type: array x-kubernetes-list-type: atomic logsEndpoint: description: |- LogsEndpoint is the Loki query endpoint for forwarded application logs. Populated when logs is configured and its LokiStack is ready. Unlike usageLogsEndpoint this is a read endpoint: the ClusterLogForwarder addresses the LokiStack by name rather than by URL, so there is no write endpoint to publish. type: string observedGeneration: description: |- ObservedGeneration is the most recent .metadata.generation observed by the controller. It allows consumers to determine whether the controller has processed the latest spec changes. format: int64 type: integer phase: description: Phase is the top-level lifecycle phase of the module. type: string releases: description: Releases is the list of deployed component releases. items: description: ComponentRelease describes a single software component's release metadata. properties: name: description: Name is the component name, used as the merge key in lists. type: string repoUrl: description: RepoURL is the source repository URL for this component release. type: string version: description: Version is the semantic version of the component. type: string required: - name type: object type: array x-kubernetes-list-map-keys: - name x-kubernetes-list-type: map url: description: URL is the dashboard endpoint when available. type: string usageLogsEndpoint: description: |- UsageLogsEndpoint is the Loki OTLP endpoint for sending usage logs. Populated when usage-log storage is configured and its LokiStack is ready. type: string usageLogsForwarding: description: |- UsageLogsForwarding names the remote usage-log exporters carried by the deployed collector. It reports what passed validation and was rendered, so it is empty when no collector is deployed, which the UsageLogsCollectorAvailable condition explains. items: type: string type: array type: object type: object x-kubernetes-validations: - message: Monitoring name must be default-monitoring rule: self.metadata.name == 'default-monitoring' served: true storage: true subresources: status: {} status: acceptedNames: kind: Monitoring listKind: MonitoringList plural: monitorings singular: monitoring conditions: - lastTransitionTime: "2026-10-30T18:07:22Z" message: no conflicts found reason: NoConflicts status: "True" type: NamesAccepted - lastTransitionTime: "2026-10-30T18:07:22Z" message: the initial names have been accepted reason: InitialNamesAccepted status: "True" type: Established storedVersions: - v1alpha1