sourceRef: kind: OCIRepository name: cozystack-platform namespace: cozy-system path: / migrations: enabled: false # The image digest is NOT hand-edited alongside targetVersion. The release # build rebuilds the migrations image from this same source tree (which # carries migrations/ and the etcd-migrate binary) and restamps this pin # in the same commit via `make image-migrations` (yq --inplace) — so image and # targetVersion are only consistent at a release tag, not mid-PR. The digest # below therefore lags targetVersion in-tree by design; run-migrations.sh # refuses to advance past a migration file missing from the image (exit 1), so # a stale pin fails loudly rather than silently skipping the etcd adoption. image: ghcr.io/cozystack/cozystack/platform-migrations:v1.6.1@sha256:a34e7156a52dc55b27662917e5f9d5bbea671188d8db233296d0a98c800dc6c6 targetVersion: 54 # Adopt legacy etcd clusters onto the v1alpha2 operator WITHOUT the mandatory # pre-adoption safety snapshot (migration 50). Leave false unless migration 50 # has actually refused to proceed and you accept the risk: adoption rewires # ownership of LIVE etcd storage, and a botched adoption on a tenant # control-plane etcd is UNRECOVERABLE with no snapshot. # # Migration 50 refuses when it cannot resolve, or cannot trust, a snapshot # destination — backups disabled, an external S3 whose credentials were never # staged, SeaweedFS not ready at upgrade time, or a bucket it cannot classify. # Those are individually-supported configurations, so rather than leave such a # cluster permanently unable to upgrade, this flag lets an operator proceed # deliberately. Prefer fixing the condition the migration names in its log: # the migration is idempotent, so re-running after the fix is the safe path, # and this flag is the last resort when there is nothing to fix. # # Reset it to false once the upgrade is through, or the next platform upgrade # that adds an etcd migration will skip its snapshot too. etcdAdoptSkipBackup: false # Bundle deployment configuration bundles: system: enabled: false variant: "isp-full" # Options: "isp-full", "isp-full-generic", "isp-hosted", "distro-full" iaas: enabled: false # gpu-operator variant selector — applies when cozystack.gpu-operator is # in bundles.enabledPackages. "default" runs the vfio-pci passthrough # stack (whole GPU → one VM); "vgpu" runs the vGPU Manager stack. The # platform mirrors this into the KubeVirt CR: passthrough auto-wires the # HostDevices feature gate plus a default permittedHostDevices.pciHostDevices # table covering common NVIDIA datacenter GPUs (vendor 10DE); vgpu # auto-wires permittedHostDevices.mediatedDevices plus a starter # mediatedDevicesConfiguration. Operators with additional or non-NVIDIA # cards extend the defaults via gpu.permittedHostDevices / # gpu.mediatedDevicesConfiguration / gpu.replaceDefaults below. gpuOperatorVariant: default paas: enabled: false naas: enabled: false disabledPackages: [] enabledPackages: [] # Network configuration networking: clusterDomain: "cozy.local" podCIDR: "10.244.0.0/16" podGateway: "10.244.0.1" serviceCIDR: "10.96.0.0/16" joinCIDR: "100.64.0.0/16" # KubeOVN master nodes override (optional) # By default, KubeOVN helm chart uses `lookup` to find control-plane nodes # by label `node-role.kubernetes.io/control-plane`. On fresh clusters or # during initial deployment, lookup may return empty results. # Set this to comma-separated list of master node IPs to override. kubeovn: MASTER_NODES: "" # Service publishing and ingress configuration publishing: host: "example.org" ingressName: tenant-root # Optional namespace of a SEPARATE Gateway / ingressClass that system # components attach their admin routes to (currently Keycloak) — e.g. one # bound to a private IP, unreachable from the public internet. Empty means # admin endpoints share the same ingress as everything else (ingressName). # The private Gateway itself is NOT created by cozystack; provision it out # of band, then point this at its namespace to move admin traffic onto it. ingressNameAdmin: "" exposedServices: - api - dashboard - vm-exportproxy - cdi-uploadproxy apiServerEndpoint: "" # example: "https://api.example.org" externalIPs: [] # Native loadBalancerClass for the host ingress. When externalIPs is empty the # host ingress publishes its Service as type: LoadBalancer; set this to the # loadBalancerClass of the LoadBalancer controller that should handle it. The # admin provisions the matching address pool / announcer out of band (a MetalLB # IPAddressPool, a Cilium LB-IPAM pool, a cloud LB, etc.). Empty lets the # cluster's default LoadBalancer controller claim the Service. # spec.loadBalancerClass is immutable: on a cluster whose host ingress Service # already exists as type: LoadBalancer, setting, changing, or clearing this # value requires recreating that Service once (the chart fails early with the # exact command). loadBalancerClass: "" # Enable PROXY-protocol on the host ingress-nginx and auto-deploy # ouroboros (system/ouroboros) to fix the resulting hairpin-NAT # problem (intra-cluster traffic to the cluster's own public hostnames # arrives at ingress-nginx without the PROXY header it now requires). # Single cozystack-side switch: flipping this to true configures both # pieces in one go — ingress-nginx use-proxy-protocol and the # cozystack.ouroboros Package CR. # # TALOS RE-RENDER NOTE (host scope only): the host CoreDNS is a # Talos-managed Deployment; ouroboros mutates its live Corefile in # place between BEGIN/END markers. A Talos machine-config push or # upgrade re-renders the Corefile and overwrites the markers — there # is a flap window of up to one ouroboros reconcile loop (bounded # by `controller.resync`, default 10 minutes) until the controller # re-applies the block. The reconcile loop is ALSO event-driven on # Ingress/Gateway watches, so on a busy cluster the window often # closes much sooner — but on a stable production cluster with no # incidental Ingress/Gateway churn, the upper bound is the resync # interval. In-cluster DNS for hairpinned hostnames briefly returns # the upstream LB IP instead of the proxy ClusterIP during that # window, which fails the same way pre-PR behaviour fails. # Acceptable, but worth knowing during a Talos roll. # # PRECONDITION: the upstream L4 load balancer / WAN edge in front of # ingress-nginx MUST already be injecting PROXY-protocol v1 headers # before flipping this flag. Without that, every external request # arrives at ingress-nginx without the PROXY header, ingress-nginx # closes the connection, and ALL ingress traffic breaks. cozystack # cannot configure that upstream LB for you — it lives outside the # cluster (cloud LB, F5, MetalLB+haproxy, hcloud-cloud-controller, # etc.). PROXY-protocol frames travel from the upstream LB to # ingress-nginx (the LB opens a fresh TCP connection to the backend # and prepends the frame on that connection), not back to the # client — `nc` from a laptop will never see one. Pick one of: # # * tcpdump --interface any 'port 80 or port 443' -A on the node # hosting ingress-nginx and watch for a leading "PROXY TCP4 ..." # frame on inbound TCP from the LB BEFORE flipping this flag. # * make any external HTTP request after the LB-side change but # before flipping this flag, and watch # `kubectl --namespace cozy-ingress-nginx logs deploy/ingress-nginx-controller` # for "client sent invalid proxy protocol header" — that error # means the LB started injecting PROXY frames but ingress-nginx # is not yet configured to accept them, which is the transition # state this flag is meant to resolve. # # If neither check shows PROXY frames, fix the upstream LB before # touching this flag. Leave it false on clusters where PROXY-protocol # is not yet wired at the upstream LB; ouroboros wastes resources # when the bug it fixes does not exist. # # FAN-OUT NOTE: this flag affects ONLY the host control plane. To # turn the same hairpin fix on inside a tenant cluster, also set # `addons.ouroboros.enabled: true` in the per-tenant Kubernetes CR # (and `addons.ingressNginx.enabled: true` is a hard precondition # there). The flag does not cascade into tenants on its own. # # DISABLE PATH: flipping this back from true to false has TWO # asymmetric effects. ingress-nginx side: the switch travels through # _cluster.proxy-protocol in the cozystack-values Secret, so the next # reconcile re-renders the host ingress-nginx (extra/ingress) without # the use-proxy-protocol / real-ip-header / enable-real-ip keys # (cozystack deliberately never sets use-forwarded-headers or # compute-full-forwarded-for — those would allow any upstream proxy # to spoof X-Forwarded-For without a paired proxy-real-ip-cidr — see # the rationale in extra/ingress/templates/nginx-ingress.yaml). The # cozystack.ingress-application Package stays the bare default # throughout; the keys never ride on it. ingress-nginx then stops # accepting PROXY-protocol headers. If the upstream L4 LB is # still prepending PROXY frames at that moment, every external # request to ingress-nginx breaks until the LB is also reconfigured # — flip the LB OFF FIRST, then flip this flag. ouroboros side: # stops emitting the cozystack.ouroboros Package CR, but every Package # CR carries `helm.sh/resource-policy: keep`, so Helm leaves the # existing Package on the cluster, ouroboros stays installed, and # the live Corefile rewrite block keeps pointing at the still-running # ouroboros-proxy Service. Flag-flip alone leaves ouroboros idempotent. # # To actually uninstall ouroboros, the operator removes the Package # CR explicitly: # # kubectl delete package.cozystack.io cozystack.ouroboros # # or adds the package name to bundles.disabledPackages. THAT is the # path that triggers the chart's pre-delete Helm hook # (charts/ouroboros/templates/coredns-cleanup-hook.yaml, vendored at # 0.8.0) — the hook quiesces the controller, sed-strips the # BEGIN/END block from the live kube-system/coredns Corefile, and # restores the cleaned ConfigMap via kubectl replace. The hook is # automatic; operators do NOT need to run a manual sed recipe in # the normal disable path. Documentation of the hook's exact # behaviour lives in the upstream chart's README. # # Manual cleanup recipe (only if the chart's pre-delete hook fails # to land — controller pod stuck in CrashLoop blocking the quiesce # step, ConfigMap RBAC drift on the namespace, helm uninstall # interrupted before the hook ran). Uses a JSON merge-patch so # labels, annotations, and other data keys on the ConfigMap — # including any Talos-managed metadata — are preserved: # # # === BEGIN cleanup-recipe === # existing=$(kubectl --namespace kube-system get configmap coredns \ # --output jsonpath='{.data.Corefile}') # cleaned=$(printf '%s\n' "$existing" \ # | sed '/# === BEGIN ouroboros/,/# === END ouroboros ===/d') # kubectl --namespace kube-system patch configmap coredns \ # --type merge \ # --patch "$(jq --null-input --arg c "$cleaned" \ # '{data: {Corefile: $c}}')" # kubectl --namespace kube-system rollout restart deployment/coredns # # === END cleanup-recipe === proxyProtocol: false # Acknowledgement gate for the helm.sh/resource-policy: keep # asymmetry (NOT a substitute for the chart's pre-delete cleanup # hook — the hook handles the Corefile patch automatically when # the chart actually uninstalls). The hazard this gate catches: # flipping publishing.proxyProtocol from true to false stops # emitting the cozystack.ouroboros Package CR, but resource-policy: # keep means Helm leaves the existing Package on the cluster. # ouroboros keeps running, the cleanup hook never fires, the # rewrite block stays live. The platform render fails until the # operator either restores proxyProtocol: true OR runs `kubectl # delete package.cozystack.io cozystack.ouroboros` (which lets # the chart actually uninstall and the hook run) and sets this # flag to true to confirm. Once the cluster has been clean for # one reconcile cycle, flip back to false. # # KNOWN HOLE: the guard keys off a `lookup` for the cozystack.ouroboros # Package CR on the cluster. An operator who manually # `kubectl delete package cozystack.ouroboros` before flipping the # flag back bypasses the check entirely (the lookup returns nil, the # render proceeds). In the chart 0.8.0 that path is mostly safe — # `kubectl delete package` triggers helm uninstall and the chart's # pre-delete hook patches the Corefile automatically. The hole is # the rare case where the hook itself fails (controller pod stuck, # ConfigMap RBAC drift, hook timeout) and the operator never # noticed. The values comment + the acknowledge gate are # defence-in-depth, not an airtight lock; an operator deliberately # working around them gets to keep the broken pieces. proxyProtocolAcknowledgeUnclean: false certificates: solver: http01 # "http01" or "dns01" issuerName: letsencrypt-prod # Shared wildcard issuance on the default ingress-nginx path # (gateway.enabled=false). Opt-in, OFF by default. When set to true # with solver=dns01 and no operator-provided wildcardSecretName, the # platform issues ONE wildcard Certificate (*. + # ) via the DNS-01 ClusterIssuer and serves it as the # ingress controller's default SSL certificate, so system services # (dashboard, grafana, keycloak, harbor, …) stop minting a per-host # ACME cert each. This avoids the Let's Encrypt per-domain rate limit # once a deployment exceeds ~50 endpoints, matching the Gateway API # path which issues a per-apex wildcard in dns01 mode. # # Ignored when solver=http01 (HTTP-01 cannot issue wildcards) and # when gateway.enabled=true (the TenantGateway controller issues the # wildcard there). # # COVERAGE CAVEAT — same contract as wildcardSecretName below: a # single-label wildcard *. covers . # but NOT a custom service host outside it (e.g. a keycloak # ingress.host / harbor host / grafana host set to auth.example.com, # or a nested a.b.). When this is true, services whose # host is not covered fall back to the default SSL certificate and # would serve the wrong certificate. Only enable it when every # exposed system service uses a . host (the # default), or provide a covering wildcardSecretName instead. Left # OFF by default precisely so a dns01 cluster with a custom service # host is never silently switched on upgrade. # # BLAST RADIUS — like wildcardSecretName, the chosen name rides the # _cluster channel, which every child tenant inherits verbatim. A # child tenant that inherits the root ingress has nested service # hosts (..) that *. does NOT # cover; enabling this makes those services drop per-host ACME and # serve the root default certificate too. This is not root-tenant # scoped — only enable it when child-tenant hosts are also covered # (or left on the Gateway path). Per-tenant wildcards are tracked # separately. # # FIRST-ISSUANCE WINDOW: when this is turned on, consumers drop their # per-host certs immediately, but the DNS-01 wildcard takes a few # minutes to issue. Until the Secret is populated ingress-nginx serves # its self-signed default cert (browser warning), then self-heals — # the same delay per-host ACME has on first issue, which an # operator-provided wildcardSecretName avoids only by pre-existing. wildcard: false # Operator-provided wildcard certificate. When set, platform # services and the root tenant's ingress/Gateway serve under this # pre-existing TLS Secret instead of minting per-host ACME certs. # The Secret must already exist in the publishing namespace — the # one that runs the root ingress controller / Gateway, which follows # publishing.ingressName (tenant-root by default) — be of type # kubernetes.io/tls, and cover the root host (typically a wildcard # *. + ). Only the # NAME is distributed through the platform values channel — the # cert/key material is never broadcast. Leave empty to keep ACME # issuance (solver/issuerName above). # # Child tenants are covered automatically: the platform controller # replicates this Secret into every tenant namespace that runs its own # ingress controller or Gateway, so each per-tenant termination point # serves the wildcard from its own namespace (no cross-namespace Secret # read, no widened tenant RBAC). No extra input — the same name set # here drives both the consumers and the replication. The replica # carries the wildcard private key into each terminating tenant # namespace (the same exposure as the per-host ACME Secret it replaces, # now shared across tenants), and covers a child apex only if the # certificate's SAN list does — a single *. does not match # *., so supply SANs covering the child apexes you serve. # On a freshly-created tenant the replica may land a moment after the # tenant's ingress controller starts. The window is bounded: the # platform controller creates the replica within one reconcile, and # ingress-nginx watches its default-ssl-certificate Secret and adopts # it when it appears (no restart needed). Until then ingress-nginx logs # a warning and serves its built-in certificate. wildcardSecretName: "" # Rate-limit note: every tenant with gateway=true issues one # Certificate for its wildcard + apex hostnames. If many tenants share # the same apex domain with issuerName=letsencrypt-prod, the cluster # can hit the Let's Encrypt limits (50 certs / registered domain / # week, 5 duplicate certs / week, 300 new orders / account / 3h). # Use letsencrypt-stage for non-production clusters or gate the # number of certificates per tenant via tenant.spec.resourceQuotas # with count/certificates.cert-manager.io. See # https://letsencrypt.org/docs/rate-limits/. # # DNS-01 solver configuration. Read only when solver=dns01. The # provider key selects which sub-block is consumed; others are # ignored. Cloudflare keeps backwards-compatible defaults so the # most common opt-in path (cloudflare token + dns01) needs only # solver=dns01 + dns01.cloudflare.secretName. dns01: provider: cloudflare # cloudflare | route53 | digitalocean | rfc2136 cloudflare: secretName: cloudflare-api-token-secret secretKey: api-token route53: region: "" accessKeyID: "" secretName: "" secretKey: secret-access-key digitalocean: secretName: digitalocean-api-token-secret secretKey: access-token rfc2136: nameserver: "" tsigKeyName: "" tsigAlgorithm: HMACSHA256 secretName: "" secretKey: tsig-secret-key # Authentication configuration authentication: oidc: enabled: false insecureSkipVerify: false keycloakExtraRedirectUri: "" # In-cluster URL of the KeyCloak realm, used for backend-to-backend requests. oauth2-proxy runs # with --skip-oidc-discovery and sends every backend call (token, jwks, userinfo, logout) to this # URL, while browser-facing redirects keep pointing at the external host. # # This is the default path: the bundled KeyCloak is the only supported provider, so those calls # have no reason to leave the cluster. Taking the external hostname instead would route them # through public DNS and the root ingress — which does not serve yet on a fresh install, leaving # the dashboard permanently down. # # The keycloak-http Service has no TLS listener, so these backend calls travel as plaintext HTTP # between pods, as keycloak-configure's own admin calls to the same address already do. # # Override only for a KeyCloak that does not live at the standard in-cluster address. Setting it # to an empty string restores full OIDC discovery against the external issuer. keycloakInternalUrl: "http://keycloak-http.cozy-keycloak.svc:8080/realms/cozy" # Gateway API configuration gateway: # Enable Gateway API support across the platform. When true: # - cert-manager ClusterIssuers use an http01.gatewayHTTPRoute solver # that attaches to the root tenant's Gateway, so Certificate issuance # works for tenants whose ingress is via Gateway API rather than # ingress-nginx. # - Exposed services (dashboard, keycloak, harbor, bucket, grafana, # cozystack-api, vm-exportproxy, cdi-uploadproxy) render an # HTTPRoute attached to the tenant's Gateway. # Per-tenant opt-in is still governed by tenant.spec.gateway=true, which # materialises the Gateway itself. This flag only controls platform-wide # Gateway API integration (cert-manager solver + per-service HTTPRoutes). enabled: false # Namespaces that are allowed to attach HTTPRoute or TLSRoute to a tenant # Gateway. The publishing tenant namespace is always included implicitly. # Additional entries must be the exact namespace name (matched on the # built-in kubernetes.io/metadata.name label). Tenants not on this list # cannot attach a route to somebody else's Gateway, which prevents # hostname hijacking across tenants. # # The `default` namespace is included because the Kubernetes API's # TLSRoute (shipped by the cozystack-api package) has to live next to # the `kubernetes` Service it points at, which is always in `default`. attachedNamespaces: - cozy-cert-manager - cozy-dashboard - cozy-keycloak - cozy-system - cozy-harbor - cozy-bucket - cozy-kubevirt - cozy-kubevirt-cdi - cozy-monitoring - cozy-linstor-gui - default # Platform monitoring configuration. monitoring: # Whether the root tenant (tenant-root) hosts the platform # VictoriaMetrics/VictoriaLogs stack, i.e. Tenant/root spec.monitoring=true. # The platform centralises metrics and logs in tenant-root, and # cozystack-basics publishes vlinsert-generic / vminsert-* ExternalName # Services in cozy-monitoring that redirect there. When the root tenant has # monitoring disabled those redirects dead-end and fluent-bit silently drops # logs (issue #3181), so the ExternalNames are only created when this is # true. This is the single render-time source of truth for that gate: # changing it re-renders cozystack-basics (helm-controller watches the # cozystack-values Secret it flows into). Nothing in the charts sets # Tenant/root spec.monitoring — it is a runtime choice on the Tenant CR # (default false; the standard install enables it out-of-band). The default # here is true only to preserve the historical always-create behaviour; # operators MUST set it to match their actual Tenant/root spec.monitoring. rootEnabled: true # Backup storage overrides for the platform-managed cozy-default BackupClass. # Everything set here is forwarded verbatim into the emitted # cozystack.backupstrategy-controller Package CR as # components.backupstrategy-controller.values.backupStorage, so it lands on the # backupstrategy-controller HelmRelease and deep-merges over that chart's own # backupStorage defaults (packages/system/backupstrategy-controller/values.yaml # documents every knob: provisionBucket, bucketName, endpoint, region, # forcePathStyle, systemSecretName, systemNamespaces, …). Admins set this via # spec.components.platform.values.backupStorage on the # cozystack.cozystack-platform Package — see docs/operations/backup-classes.md. # Empty (the default) forwards nothing and keeps the child chart defaults. backupStorage: {} # Pod scheduling configuration scheduling: globalAppTopologySpreadConstraints: "" # UI branding configuration. The whole map is propagated verbatim into # _cluster.branding (the cozystack-values Secret) and consumed by the dashboard # (config.json) and Keycloak realm provisioning. # # Recognized keys: # brandName: realm displayName (the Keycloak login title reads it as # "Sign in to "). # brandHtmlName: realm displayNameHtml (HTML shown in the login header). # loginTheme: Keycloak login theme name; selected as the realm login # theme and used as the theme directory/name. # loginThemeImage: OCI image carrying that theme under /themes/. When set # together with loginTheme, the keycloak chart mounts it via # an init container, so the theme ships without patching the # StatefulSet or the keycloak package values. # # Example: # branding: # brandName: "Acme Platform" # brandHtmlName: "Acme Platform" # loginTheme: acme # loginThemeImage: registry.example.com/acme-keycloak-theme:v1 branding: {} # Container registry mirrors configuration # # Example: # registries: # mirrors: # docker.io: # endpoints: # - http://10.0.0.1:8082 # ghcr.io: # endpoints: # - http://10.0.0.1:8083 # gcr.io: # endpoints: # - http://10.0.0.1:8084 # registry.k8s.io: # endpoints: # - http://10.0.0.1:8085 # quay.io: # endpoints: # - http://10.0.0.1:8086 # cr.fluentbit.io: # endpoints: # - http://10.0.0.1:8087 # docker-registry3.mariadb.com: # endpoints: # - http://10.0.0.1:8088 # config: # "10.0.0.1:8082": # tls: # insecureSkipVerify: true registries: {} # Resource allocation ratios resources: cpuAllocationRatio: 10 memoryAllocationRatio: 1 ephemeralStorageAllocationRatio: 40 # GPU host-device wiring for VirtualMachine workloads. Auto-injected into the # KubeVirt CR's permittedHostDevices when bundles.enabledPackages contains # cozystack.gpu-operator. Without it the admission webhook rejects any VM # that references a GPU host-device by resourceName. gpu: # When false (default), the lists below are appended to the platform's # NVIDIA defaults. When true, the user lists fully replace the defaults # — use this for clusters with only non-NVIDIA accelerators or where a # strictly curated allowlist is required. replaceDefaults: false permittedHostDevices: # PCI passthrough devices. Always rendered when non-empty regardless of # gpuOperatorVariant — pciHostDevices covers both the vfio-pci passthrough # path (default variant) and the post-kubevirt#16890 SR-IOV vGPU path # (vgpu variant on Ada Lovelace / Blackwell, where VFs are advertised # via pciHostDevices, not via mediatedDevices). Default-table coverage: # H100, H200, A100 PCIe/SXM, A40, A30, A10, L40, L40S, L4, T4, V100, # V100S (PCI vendor 10DE). Item shape matches KubeVirt's pciHostDevices: # - pciVendorSelector: "10DE:2335" # resourceName: nvidia.com/GH100_H200_SXM_141GB # externalResourceProvider: true pciHostDevices: [] # Mediated (mdev) vGPU devices — pre-kubevirt#16890 path used by # Pascal–Ampere on the legacy mdev driver branch. Default-table coverage: # A100-40C/80C, A40-24Q/48Q, A30-24C, A10-24Q, V100D-32C, T4-16Q. # Item shape matches KubeVirt's mediatedDevices: # - mdevNameSelector: NVIDIA A100-40C # resourceName: nvidia.com/A100-40C # externalResourceProvider: true mediatedDevices: [] # mediatedDevicesConfiguration makes KubeVirt itself create mdevs on the # node (vgpu variant only). The platform ships NO default here: mdev # creation is delegated to the GPU Operator's vGPU Device Manager # (name-based), and the mediatedDeviceTypes ids below are numeric # nvidia-NNN sysfs indices that vary per GPU SKU and driver branch — no # value is portable, so look yours up on the host # (/sys/bus/pci/devices//mdev_supported_types/*/name) before setting # it. Supplying it opts into KubeVirt-driven creation on top of the # Device Manager. Helm's mergeOverwrite semantics apply: a top-level key # you supply REPLACES that key wholesale rather than appending. Shape # matches KubeVirt's MediatedDevicesConfiguration: # mediatedDeviceTypes: # - nvidia-740 # nodeMediatedDeviceTypes: # - nodeSelector: # nvidia.com/gpu.product: NVIDIA-L40S # mediatedDeviceTypes: # - nvidia-740 mediatedDevicesConfiguration: {} # NVIDIA vGPU Manager container image (vgpu variant only). The .run is # proprietary, not redistributable, so the platform cannot ship default # tags — the operator builds the container per # https://github.com/NVIDIA/gpu-driver-container and supplies the # private-registry coordinates here. The platform forwards these as # components.gpu-operator.values.gpu-operator.vgpuManager to the emitted # cozystack.gpu-operator Package CR when bundles.iaas.gpuOperatorVariant # is vgpu. Forwarding triggers when ANY of repository, version, image # (non-default), or imagePullSecrets is set — partial values still # propagate so a private-registry-with-default-tag setup is not # silently dropped. vgpuManager: repository: "" image: vgpu-manager version: "" imagePullSecrets: [] # vGPU Device Manager controls whether nvidia.com's # `vgpu-device-manager` DaemonSet is deployed (vgpu variant only). The # DaemonSet walks /sys/class/mdev_bus/ to auto-create mediated devices # from the mediatedDeviceTypes list. Default-off because that path # only exists on Pascal–Ampere (V100, T4, A100, A30, …) with the mdev # driver branch — on Ada Lovelace / Blackwell (L4, L40, L40S, B100) # with the vGPU 17/20 driver branch the directory is missing and the # DaemonSet crash-loops with "no parent devices found". Flip to true # on Pascal–Ampere clusters; leave false on Ada/Blackwell and supply # SR-IOV VFs via .gpu.permittedHostDevices.pciHostDevices instead. # When true the platform also lets the default name-based mediatedDevices # exposure list from files/gpu-vgpu-defaults.yaml flow into the KubeVirt # CR; when false those defaults are suppressed (advertising mediated # resources that nothing can ever allocate is a worse footgun than # missing entries). vgpuDeviceManager: enabled: false