mirror of
https://github.com/cozystack/cozystack.git
synced 2026-11-04 19:17:20 +09:00
fix/e2e-postprep-timeout
1547
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
e1781ac407 |
ci(build): route flux-plunger and kubeovn-plunger through $(BUILDER)
These two recipes spell out their buildx flags instead of using $(BUILDX_ARGS), so they never received --builder and ran on the default docker driver. After the mode=max migration that became a hard failure -- "Cache export is not supported for the docker driver" -- since the embedded docker driver cannot export a registry cache. Add the same conditional --builder flag $(BUILDX_ARGS) carries, so WRITE_CACHE=1 builds route to the docker-container builder; an empty BUILDER still emits no flag for local builds. Part of #2937. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com> |
||
|
|
a576f33461 |
refactor(build): mode=max registry cache with a main-only warmer
`--cache-to type=inline` only exports the final stage. 25 of 38 Dockerfiles are multistage, so the expensive `builder` stages (Go/Node compiles) were never cached even with a warm tag. Switch every image to a shared mode=max registry cache. - New `cache-args` macro (hack/common-envs.mk) emits `--cache-from` always and `--cache-to … mode=max` only when WRITE_CACHE=1, so PR builds stay read-only and concurrent PRs never race on the cache ref (the 409 class #2711 fixed for tags). oci-mediatypes/image-manifest keep the cache manifest portable across registries. - Cache ref is CACHE_REGISTRY/<img>:buildcache, co-located with the build registry (CACHE_REGISTRY now defaults to $(REGISTRY)). - New build-main.yaml warms :buildcache on every push to main (WRITE_CACHE=1), serialized via concurrency. All 31 package image recipes converted from the inline cache-from/cache-to pair to `$(call cache-args,…)`; ubuntu-container-disk keeps a per-k8s-version cache tag. Verified with `make -n image` across all packages in both PR (read-only) and main (mode=max write) contexts. Part of #2937. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com> |
||
|
|
e69d2682a0 |
fix(seaweedfs): drop volumeSizeLimitMB so multiple collections fit
Cozystack overrides the upstream seaweedfs volumeSizeLimitMB from 1000 to 30000 (30 GB), but the e2e sandbox provisions only a 10 GiB PVC per volume server. With maxVolumes=0 (auto), seaweedfs computes maxVolumes as int(10240 / 30000) → 0, then rounds up to 1, so each volume server can host exactly 1 logical volume. With defaultReplication=001 (one replica on a different node within the same rack) two volume servers share that single volume, giving the cluster a hard limit of one writable collection at a time. Since #2716 added a default bucket-cozy-backups Bucket to every tenant-root, that bucket now grabs the only slot on install. Any second collection — the bucket E2E (bucket-test in tenant-test), a tenant app's own bucket, etc. — sits in 'assign volume: No writable volumes' forever, and mc cp hangs until the test times out. Master logs reflect this clearly: failed to find writable volumes for collection:bucket-... replication:001 ttl: error: No writable volumes and no free volumes left topo failed to pick 1 from 0 node candidates volume_growth.go:135 create 6 volume, created 0: Not enough data nodes found! Lower volumeSizeLimitMB back to the upstream chart default of 1000, which makes a 10 GiB PVC fit ~10 logical volumes per server and unblocks all per-collection bucket workloads on small sandboxes. Production clusters still get plenty of headroom — volume size is a soft cap, not a preallocation. Signed-off-by: Ivan Okhotnikov <ivan.okhotnikov@aenix.io> |
||
|
|
562239d90c |
fix(seaweedfs): restore s3 Service name to chart-prefix form
The seaweedfs 4.31 upstream bump (#2834) switched the s3 Service name from "$chartname-s3" (built with the seaweedfs.name helper, evaluates to "seaweedfs-s3") to the seaweedfs.componentName helper, which is release-name based and now evaluates to "$release-s3" — "seaweedfs- system-s3" for the tenant-root deployment. The bats E2E asset hack/e2e-apps/bucket.bats hard-codes "service/seaweedfs-s3" for the port-forward that sets up its S3 client; backup-controller and other in-cluster consumers also referenced the legacy name. After the bump, the legacy Service is gone and the port-forward immediately exits, the test then times out on the 30-second nc poll for localhost:8333. Restore the legacy Service name. Internal references inside the chart (s3-deployment -filer=, etc) keep using componentName for the filer endpoint, so this change only re-exposes the public-facing name without touching the internal topology. Signed-off-by: Ivan Okhotnikov <ivan.okhotnikov@aenix.io> |
||
|
|
f8c83bfd2f |
fix(seaweedfs): restore -lock BucketClass and -readonly BucketAccessClass
The seaweedfs 4.31 upstream bump (#2834) rewrote packages/system/seaweedfs/charts/seaweedfs/templates/cosi/cosi-bucket-class.yaml from scratch and silently dropped the supplementary COSI resources that cozystack ships on top of the upstream chart: - BucketClass {name}-lock (object lock, COMPLIANCE mode, 365 days retention) — used by apps that store immutable backups - BucketAccessClass {name} parameters.accessPolicy: readwrite — the explicit grant for the default access class - BucketAccessClass {name}-readonly (accessPolicy: readonly) — used by every Bucket app that declares readonly users apps/bucket still renders BucketAccess resources that reference {name}-readonly, but the class no longer exists, so the COSI controller never picks the BucketAccess up: no finalizer is added, status.accessGranted stays empty, and the bucket E2E test waits 300s and times out on the viewer access. The admin (readwrite) access class still works because it falls back to the default BAC. Restore the three resources so the system chart again matches the shape that packages/extra/seaweedfs/templates/client/cosi-bucket-class.yaml already ships for the client topology (where this never regressed). Signed-off-by: Ivan Okhotnikov <ivan.okhotnikov@aenix.io> |
||
|
|
4b9b1b4f96 |
fix(capi): add startupProbe to capi-controller-manager to survive cert provisioning delay
The capi-controller-manager liveness probe has no initialDelaySeconds (defaults to 0), giving the container only 30s (3×10s) to serve /healthz. In controller-runtime, the health endpoint starts after the webhook server, which needs its TLS cert from cert-manager. During a loaded install, cert-manager is busy issuing many certs simultaneously and the CAPI webhook cert can take >30s — causing a kill loop (6+ restarts observed in CI). A startupProbe with failureThreshold=30 gives up to 300s for the initial startup, after which the regular livenessProbe takes over for ongoing health monitoring. This is the standard pattern for slow-starting containers with external dependencies. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com> |
||
|
|
97cf5857a3 |
fix(prometheus-operator-crds): clean chart dir before helm pull
Add `rm -rf charts/prometheus-operator-crds` before `helm pull` in the update target so stale files from previous chart versions don't linger across updates. This matches the convention used by cilium, external-secrets-operator, external-dns, and cert-manager Makefiles. Address review feedback from gemini-code-assist on packages/system/prometheus-operator-crds/Makefile:9. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com> |
||
|
|
dbbaca16eb |
fix(prometheus-operator-crds): ship full upstream CRD bundle
The chart previously stripped the bundle to 4 CRDs (ServiceMonitor, PodMonitor, PrometheusRule, Probe) — the set VictoriaMetrics operator needs for service discovery. This was correct when the chart was vendored inside system/victoria-metrics-operator (commit |
||
|
|
484d73bf78 |
fix(seaweedfs): restore S3 TLS and COSI provisioner SA after 4.31 bump
The 4.31 chart bump (#2834) broke E2E for every PR: tenant-root seaweedfs-system never becomes ready. 1. S3 served plaintext. Until 4.05 the -cert.file/-key.file args were rendered whenever enableSecurity was set, so weed s3 served TLS on the main port (8333); 4.31 nested them under 'if s3.httpsPort' and we ship httpsPort=0, so s3 spoke HTTP while the HTTPS probes, the ingress backend-protocol and the COSI sidecar endpoint all expected HTTPS ('server gave HTTP response to HTTPS client'). Restore the 4.05 behaviour via patch. 2. COSI provisioner ServiceAccount mismatch. cosi-service-account.yaml and the ClusterRoleBinding name the SA <serviceAccountName>-objectstorage-provisioner, but the Deployment referenced componentName (<release>-objectstorage-provisioner). When serviceAccountName != release name (tenant-root-seaweedfs vs seaweedfs-system) the Deployment could not create pods ('serviceaccount not found'). Align the Deployment with the SA + binding. Both fixes are vendored as patches re-applied by 'make update', and covered by helm-unittest. Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Andrei Kvapil <andrei.kvapil@aenix.io> |
||
|
|
13e310fe71 | Merge branch 'main' into chore/seaweedfs-4.31 | ||
|
|
1d747b3d8d |
feat(platform): auto-wire KubeVirt permittedHostDevices and HostDevices feature gate when gpu-operator is enabled (#2768)
Closes #2765. ## What this PR does Makes the passthrough and vGPU variants of `cozystack.gpu-operator` produce a KubeVirt CR that is immediately usable, without an out-of-band `kubectl patch`. Today the gpu-operator stack reports green, `nvidia.com/<model>` shows up under node `.status.allocatable`, but every `VirtualMachine` referencing the resource via `domain.devices.hostDevices` is rejected by the admission webhook because `HostDevices` is not in `developerConfiguration.featureGates` and the resource is not listed under `permittedHostDevices`. That manual reconciliation is now driven by the platform. The change has three parts. `packages/system/kubevirt` now parameterizes the KubeVirt CR template. `developerConfiguration.featureGates` keeps its existing static defaults and appends `.Values.extraFeatureGates`; `spec.configuration.permittedHostDevices` renders verbatim from `.Values.permittedHostDevices` when set; `spec.configuration.mediatedDevicesConfiguration` does the same. Defaults stay empty so the rendered CR is byte-identical to the previous template when no overrides are supplied. The chart's `make update` target re-applies the four sed transforms after fetching the upstream CR, so refreshing the KubeVirt release version stays a single command. `packages/core/platform` adds two defaults tables under `files/`. `gpu-passthrough-defaults.yaml` covers Hopper (H100/H200), Ada Lovelace (L4/L40/L40S), Ampere (A100 PCIe/SXM, A40, A30, A10), Turing (T4) and Volta (V100/V100S); PCI vendor:device pairs are stable, `resourceName` slugs follow the `<arch>_<model>_<form>_<mem>` convention `nvidia-sandbox-device-plugin` generates as of v25.x, and `externalResourceProvider: true` is set everywhere because those resources are advertised by the sandbox plugin rather than KubeVirt's in-tree device plugin. `gpu-vgpu-defaults.yaml` covers the Pascal–Ampere mdev profile range (A100-40C/80C, A40-24Q/48Q, A30-24C, A10-24Q, V100D-32C, T4-16Q) — the same family span the upstream `vgpu-device-manager` walks `/sys/class/mdev_bus/` for. Ada Lovelace and Blackwell SR-IOV vGPU is intentionally out of scope for the default table and is expected to be advertised via the user-override hook described below. `templates/bundles/iaas.yaml` now selects between the two tables via a new `bundles.iaas.gpuOperatorVariant` knob (`default` for passthrough, `vgpu` for mediated; default is passthrough). The same variant flows through to the gpu-operator Package CR, replacing the previous always-default call. When the package is enabled, the platform injects `HostDevices` into `extraFeatureGates` plus the chosen defaults into `permittedHostDevices` for the kubevirt component's values. Operators extend or replace via top-level platform values: ```yaml gpu: replaceDefaults: false # append (default) vs. wipe-and-replace permittedHostDevices: pciHostDevices: [] # cluster-specific PCI passthrough entries mediatedDevices: [] # cluster-specific vGPU entries mediatedDevicesConfiguration: {} # extra mediated-device types / per-node mappings ``` `docs/gpu-vgpu.md` is updated to drop the manual `kubectl patch` step and describe the auto-wiring contract, the per-variant defaults, the escape hatches, and the sandbox-device-plugin `resourceName` slug convention so an operator whose node publishes a different name knows where to override. ## Test coverage `helm-unittest` covers eight branches in `packages/core/platform/tests/bundles_gpu_kubevirt_wiring_test.yaml`: gpu-operator disabled emits no extras; gpu-operator enabled at default variant emits the HostDevices gate plus `pciHostDevices`; vgpu variant switches to `mediatedDevices` plus `mediatedDevicesConfiguration`; user overrides append by default; `replaceDefaults: true` wipes the platform table; an unknown variant fails fast with a descriptive error. `packages/system/kubevirt/tests/kubevirt_cr_test.yaml` pins the empty-values render and the three populated shapes at the CR template level. `make helm-unit-tests` passes locally on the full repo. ### Release note ```release-note feat(platform): the KubeVirt CR is now auto-configured for GPU host-device passthrough (HostDevices feature gate plus permittedHostDevices populated from NVIDIA defaults) whenever cozystack.gpu-operator is in bundles.enabledPackages. Operators no longer need a manual kubectl patch to make VMs schedule against a GPU. The variant is selected via bundles.iaas.gpuOperatorVariant (default: passthrough; vgpu: mediated). Extend or replace the NVIDIA defaults via .gpu.permittedHostDevices and .gpu.replaceDefaults. **Upgrade note:** the bundle now OWNS spec.configuration.permittedHostDevices on the KubeVirt CR. If you previously hand-edited it (kubectl edit kubevirt), the first reconcile after upgrade overwrites your manual entries with the rendered NVIDIA default table. Before upgrading, move any custom entries into .gpu.permittedHostDevices (set .gpu.replaceDefaults: true to keep only your list) and verify each resourceName against what your nodes advertise (kubectl describe node <node> | grep nvidia.com/) — the default table now carries the exact slug the sandbox device plugin generates, which upper-cases the card's PCI-IDs name and keeps the Tesla/GL tokens (e.g. a Tesla T4 is nvidia.com/TU104GL_TESLA_T4), but a different plugin build can publish a different string; a mismatch makes the admission webhook reject GPU VMs on their next restart or migration. ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Bundle-managed GPU Operator with selectable passthrough vs vGPU variants; platform now injects GPU settings into KubeVirt and forwards vGPU manager overrides when enabled. * Default platform mappings for PCI passthrough and vGPU mediated-device resources added. * **Documentation** * Expanded GPU/vGPU deployment guide with bundle-managed vs manual guidance, wiring/precedence rules, resource-name conventions, and verification steps. * **Tests** * New and expanded tests for bundle→KubeVirt wiring, variant behaviors, default/override merging, and idempotent template parameterization. * **Chores** * Added Helm test target and hardened KubeVirt template update/idempotency checks. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
b6108039b7 |
feat(gpu-operator): add container variant for preinstalled host driver (#2766)
## What this PR does Add a third architectural variant to `cozystack.gpu-operator` for hosts where the NVIDIA driver and `nvidia-container-toolkit` are already installed by the distro package manager (the typical Ubuntu/Debian GPU node shape: apt-installed driver + apt-installed CT). The existing variants do not produce a working setup in that shape. `default` (passthrough) runs `vfioManager`, which unbinds the host driver to bind `vfio-pci` — with the host driver active, `k8s-driver-manager` early-exits and the bind never happens, so the GPU never reaches a pod. `vgpu` requires the proprietary NVIDIA vGPU host driver and a license server; the user-installed open or proprietary driver does not satisfy it. The new `container` variant maps onto upstream gpu-operator's third mode (`sandboxWorkloads.enabled=false` + `devicePlugin.enabled=true`) with every component that would conflict with the host install switched off: - `driver.enabled=false` — use the host driver. - `toolkit.enabled=false` — host already has `nvidia-container-toolkit`. Enabling the operator's toolkit DaemonSet would overwrite the `/etc/containerd/config.toml` the host package configured (via `nvidia-ctk runtime configure`), breaking the host runtime wiring. Matches NVIDIA's documented guidance and the existing `examples/values-native-talos.yaml` reference, which pins the same flag for the same reason. - `devicePlugin.enabled=true` — publish `nvidia.com/gpu` to the kubelet. - `vfioManager.enabled=false` — do not unbind the host driver. Upstream renders this `true` unconditionally; it only stays at zero pods because no node carries a `vm-passthrough` sandbox assignment when `sandboxWorkloads` is off — pinned off so the rendered policy matches intent. - `cdi.enabled=false` — upstream defaults this `true`, but CDI spec generation is serviced by the operator-managed toolkit DaemonSet this variant disables. An apt host doesn't auto-generate CDI specs (`nvidia-ctk cdi generate` is a manual step) and uses the classic `nvidia-container-runtime` hook, so leaving CDI on would point the device plugin at CDI injection with no specs on the host and silently break allocation. - `sandboxWorkloads.enabled=false` — regular pod workloads, not VMs. With this off, upstream `defaultWorkload` is already `container`, so no override is needed. Host prerequisite: because the operator's toolkit component is disabled, the node's containerd must already have the `nvidia` runtime registered (`nvidia-ctk runtime configure --runtime=containerd`); `apt install nvidia-container-toolkit` installs binaries only and does not wire containerd. With `driver.enabled=false` the operator uses the pre-installed host driver at its standard location, so a stock apt install needs no `hostPaths.driverInstallDir` override (Talos lands the driver under a non-standard prefix — see `examples/values-native-talos.yaml`). The bundle wiring (`packages/core/platform/templates/bundles/iaas.yaml`) already enables `cozystack.gpu-operator` as an optional package — no bundle changes required. Users opt into this variant by setting `variant: container` in their `Package` CR. Verified locally with `helm template` against `values.yaml` + `values-container.yaml`: ClusterPolicy renders with `driver.enabled=false`, `toolkit.enabled=false`, `devicePlugin.enabled=true`, `vfioManager.enabled=false`, `cdi.enabled=false`, `sandboxWorkloads.enabled=false`. Platform `helm unittest` and the `gpu-operator` variant bats suite are green. Not yet smoke-tested on a real Ubuntu GPU node — the config matches the documented apt-host wiring (legacy `nvidia-container-runtime` hook, CDI off), but an end-to-end CUDA-pod run on hardware is still owed. Closes #2764 ### Release note ```release-note feat(gpu-operator): add `container` variant for hosts with a pre-installed NVIDIA driver and nvidia-container-toolkit, exposing containerized GPU workloads via the standard NVIDIA device plugin without VFIO passthrough or vGPU. ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added a "container" GPU operator variant to support containerized GPU workloads on hosts with the NVIDIA driver and nvidia-container-toolkit. * **Documentation** * Updated variants documentation and OS support table to include the container variant and per-host requirements (including Ubuntu and Talos notes). * Clarified Talos native pod example wording. * **Tests** * Added regression tests to verify container-variant configuration and component enablement/disablement. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
28dfb40579 |
fix(dashboard): grant tenant dashboard read on cozy-public PVCs (#2843)
## What this PR does The vm-disk **source image** dropdown in the console lists `PersistentVolumeClaims` in `cozy-public` (the `vm-default-images-*` golden images) to offer them when creating a VM disk. That list is issued by the browser as the **tenant identity** (e.g. `system:serviceaccount:tenant-root:tenant-root`), but the `cozy:tenant:dashboard` Role in `cozy-public` only granted read on Flux `helmrepositories`/`helmcharts`. The list returned `403 Forbidden` and the dropdown stayed empty even when images had been enabled (e.g. via `bundles.enabledPackages`). This is identity-dependent, which is why it can look intermittent: a cluster-admin login bypasses tenant RBAC and sees the images, while any real tenant — including `tenant-root-super-admin` — hits the 403. This PR adds `get`/`list`/`watch` on `persistentvolumeclaims` to the Role. `cozy-public` is a shared public namespace, so read on its PVCs is safe to expose to every tenant dashboard subject (the Role is already bound to the tenant groups and the tenant ServiceAccount). A helm-unittest regression pins the grant. Verified with `kubectl auth can-i list pvc -n cozy-public`: - `--as=system:serviceaccount:tenant-root:tenant-root` → no (before this PR) - `--as-group=tenant-root-super-admin` → no (before this PR) - cluster-admin → yes (why it "worked" for admins) No console code changed — this is an RBAC-only fix. ### Release note ```release-note fix(dashboard): allow tenant dashboards to list VM images in cozy-public, fixing the empty source-image dropdown when creating a vm-disk ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Dashboard access permissions have been expanded to include read-level access to persistent volume claims, enabling users to manage and select images through the dashboard more effectively. * **Tests** * Added test suite to verify dashboard role permissions are correctly configured and functional. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
5982018629 |
feat(monitoring): add tenant overview dashboard (#2809)
## What Adds a cross-tenant **Tenant Overview** dashboard to the root/infra Grafana. ## Why Platform admins currently have no single view of which tenants consume what. This shows resource utilization, app counts, and health per tenant at a glance. ## Panels - **Fleet summary** — tenants, apps, running pods, CPU/memory/storage totals - **Tenant leaderboard** — per-tenant table: CPU & memory (usage vs requests), storage, pods, PVCs, app count, not-ready apps - **Top consumers** — Top-N bar gauges by CPU, memory, storage, app count - **Trends** — per-tenant CPU & memory usage over time - **Health** — pod restart rate and not-ready HelmReleases per tenant ## Details - Registered in `dashboards-infra.list` only, so it deploys to the root/`cozy-monitoring` Grafana and never exposes cross-tenant data on per-tenant instances (same pattern as `gpu/gpu-tenants`). - Apps are counted from `gotk_resource_info` HelmReleases, excluding the paired `*-system`/`cozy-*` charts. - Uses only standard cadvisor / kube-state-metrics / Flux metrics. 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## New Features * Added a Tenant Overview dashboard for comprehensive tenant infrastructure monitoring, including: * Fleet summary with tenant counts, app deployments, and aggregate resource usage * Tenant performance leaderboard with CPU, memory, and storage metrics * Top consumers visualization by resource type and app count * Historical usage trends and pod health metrics <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
ed367f30dd |
test(packages/system/seaweedfs): cover s3.trafficDistribution version gating
Pin the native s3.trafficDistribution behaviour that replaced the dropped s3-traffic-distribution.patch: PreferClose is kept on Kubernetes 1.33, auto-converts to PreferSameZone on 1.35, and the field is omitted below the 1.31 gate. Adds the helm-unittest harness (test target + suite) the package previously lacked. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la> |
||
|
|
068af203ac |
chore(packages/system/seaweedfs): bump seaweedfs to 4.31
Re-vendor the SeaweedFS Helm chart from 4.05 to 4.31. Improvements that land with the binary: the PostgreSQL filer store moves to pgx v5 with PgBouncer support and an ON CONFLICT upsert default, HTTPS certificates hot-reload without a pod restart on cert-manager rotation, and more S3/volume Prometheus metrics are exported. The S3 service now exposes a metrics port by default. Adaptations: - Drop s3-traffic-distribution.patch: native s3.trafficDistribution support landed upstream in chart 4.12. The native field is gated to Kubernetes >=1.31 and auto-converts to PreferSameZone on >=1.35, which the hardcoded patch did not do. Set s3.trafficDistribution: PreferClose in values instead. - Migrate global.* to global.seaweedfs.* in values: chart 4.18 namespaced the app-specific globals to avoid polluting the shared global namespace when the chart is used as a subchart. Covers enableSecurity, serviceAccountName, extraEnvironmentVars and monitoring. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la> |
||
|
|
8df4b0b0f1 |
feat(ingress): add proxyProtocol knob to ingress-nginx
Expose a proxyProtocol value on the Ingress application that turns on ingress-nginx use-proxy-protocol with real-ip-header=proxy_protocol and enable-real-ip. The host control plane also enables it through the _cluster.proxy-protocol switch, applied only to the external-facing ingress (the namespace named by expose-ingress). use-forwarded-headers / compute-full-forwarded-for are deliberately not set: without a paired proxy-real-ip-cidr they let clients spoof X-Forwarded-For, and the PROXY-protocol frame is already the source of truth for the client address. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la> |
||
|
|
9868c43e53 |
fix(build): read --cache-from from ghcr :latest so PR builds warm-start
PR #2711 switched PR builds to push only :pr-<N>-<sha> tags (PUBLISH_FLOATING=0) to stop concurrent-push 409 conflicts, but left --cache-from pointing at $(REGISTRY)/<img>:latest. PR builds set REGISTRY to the per-CI registry (iad.ocir.io) and never publish :latest there, so every PR build's registry cache lookup 404s and rebuilds cold. Add a CACHE_REGISTRY knob (default ghcr.io/cozystack/cozystack, where release builds do publish :latest) and point every --cache-from at it. Push targets ($(REGISTRY)) and the unique per-PR tags are unchanged, so the #2711 anti-conflict behaviour is preserved while PR builds regain a warm cache from the last release. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com> |
||
|
|
285f42aaeb |
fix(kubevirt): reinsert each GPU CR patch independently in make update
The update target gated the insertion of both the permittedHostDevices and mediatedDevicesConfiguration directives behind a single `grep permittedHostDevices` guard. A hand-merge from a newer upstream KubeVirt CR that dropped only mediatedDevicesConfiguration left permittedHostDevices in place, so the guard skipped the combined sed and mediatedDevicesConfiguration was never reinserted — then the sanity-check tail aborted the target with a non-zero exit instead of self-healing. Split the two directives into independent guarded inserts so each self-heals on its own. Reword the sanity-check failures to name the directive that failed to land and the anchor its insert keys off, instead of implying the anchor itself is missing. Add a shell regression test that strips one directive at a time and asserts `make update` restores it without duplicating the other; the update target gains a CR_FILE override so the test can drive it against a throwaway copy. Wired into the package test target and guarded to skip on BSD sed. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la> |
||
|
|
8c507fe4c5 |
feat(kubevirt): parameterize CR for host-device GPU configuration
The KubeVirt CR's developerConfiguration.featureGates list, the
permittedHostDevices block, and mediatedDevicesConfiguration are now
driven by chart values:
- extraFeatureGates is appended after the static default set so
HostDevices (or any other future gate) can be enabled without
forking the template.
- permittedHostDevices is rendered verbatim when set, allowing the
pciHostDevices (passthrough) and mediatedDevices (vGPU) shapes the
KubeVirt admission webhook requires for VMs that reference a GPU
by resourceName.
- mediatedDevicesConfiguration is rendered verbatim when set,
carrying mediatedDeviceTypes / nodeMediatedDeviceTypes for the
vGPU profile auto-creation loop.
Defaults stay empty so the rendered CR is byte-identical to the
previous template when no overrides are supplied.
The Makefile's update target re-applies the four sed transforms
in-place on templates/kubevirt-cr.yaml — it does not download anything
from upstream KubeVirt because the published CR is a near-empty stub
and would clobber the hand-curated cozystack defaults. To refresh from
a newer upstream release the operator hand-merges the new fields into
the in-tree template, then runs `make update` to re-assert the four
cozystack parameterization patches; grep sanity-checks at the end of
the target fail loudly if any anchor (developerConfiguration,
- VMExport, evictionStrategy) gets dropped during the hand-merge.
Companion helm-unittest coverage pins the default render and the
three populated shapes.
Signed-off-by: Aleksei Sviridkin <f@lex.la>
|
||
|
|
9352d3ee0e |
feat(gpu-operator): add container variant for preinstalled host driver
The two existing variants assume the host has neither the NVIDIA driver
nor the container toolkit: default unbinds the host driver to bind
vfio-pci for KubeVirt VMs, vgpu requires the proprietary vGPU host
driver and a license server. Neither path produces a working setup on a
node that already ships the driver and nvidia-container-toolkit via the
distro package manager — the most common shape of a Linux GPU node.
The new container variant surfaces the third architectural mode that
upstream NVIDIA gpu-operator already supports: sandboxWorkloads
disabled, devicePlugin enabled, with every component that would
conflict with the host install switched off.
- driver.enabled=false use the host driver
- toolkit.enabled=false host already has nvidia-container-toolkit;
enabling overwrites the containerd
config.toml the host configured via
nvidia-ctk runtime configure
- devicePlugin.enabled=true publish nvidia.com/gpu to the kubelet
- vfioManager.enabled=false do not unbind the host driver
- cdi.enabled=false CDI spec generation is serviced by the
disabled toolkit; an apt host uses the
legacy nvidia-container-runtime hook, so
pin off to match the host runtime wiring
- sandboxWorkloads.enabled=false regular pod workloads, not VMs
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
|
||
|
|
80fbfa1ed8 |
fix(networking): point host ouroboros proxy at the root-tenant ingress (#2800)
## What this PR does With `publishing.proxyProtocol: true`, the host emits a `cozystack.ouroboros` Package using the no-override Package macro, so the proxy inherits the wrapper chart default backend `ingress-nginx-controller.cozy-ingress-nginx`. That layout describes a managed Kubernetes tenant cluster, not the host: on the host, `extra/ingress` deploys ingress-nginx into the root tenant namespace as `root-ingress-controller` in `tenant-root`. The composed backend FQDN never resolves, so `ouroboros-proxy` never reaches Ready. This emits the host ouroboros Package with a `proxy.target` override derived from `publishing.ingressName` — namespace plus `<short>-ingress-controller` service name — mirroring the `trimPrefix "tenant-"` transform `extra/ingress` applies to its release namespace. The derivation reuses the existing platform invariant that `publishing.ingressName` is the namespace where the host ingress controller runs. Adds bundle helm-unittest coverage for the default ingress name and a non-default one, and corrects the misleading wrapper `values.yaml` comment that claimed the host uses `cozy-ingress-nginx`. Scope: this fixes the ouroboros readiness defect only. The separate defect where the injected nginx PROXY-protocol config keys are not consumed by the host ingress is tracked independently and not touched here. Closes #2797 ### Release note ```release-note fix(networking): point the host ouroboros PROXY-protocol proxy at the root-tenant ingress so it becomes Ready when publishing.proxyProtocol is enabled ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Enhanced proxy protocol configuration to automatically route through the appropriate ingress-nginx service based on your ingress name settings. * **Tests** * Added test coverage for proxy protocol bundle wiring and ingress service routing. * **Documentation** * Clarified proxy target configuration behavior and fallback mechanisms. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
bb322138ec |
fix(dashboard): grant tenant dashboard read on cozy-public PVCs
The vm-disk source image dropdown in the console lists PersistentVolumeClaims in cozy-public (the vm-default-images-* golden images). The browser issues that list as the tenant identity (e.g. system:serviceaccount:tenant-root:tenant-root), but the cozy:tenant:dashboard Role only granted read on Flux helmrepositories and helmcharts. The list returned 403 and the dropdown stayed empty even when the images existed. Add get/list/watch on persistentvolumeclaims to the Role. cozy-public is a shared public namespace, so read on its PVCs is safe to expose to every tenant dashboard subject. A helm-unittest regression pins the grant. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com> |
||
|
|
bc03142c08 | feat(ouroboros): bump to v0.8.0 (#2807) | ||
|
|
67b406fa1a |
fix(objectstorage-controller): propagate Bucket readiness to BucketClaim (#2792)
## What this PR does
The vendored COSI `objectstorage-controller` (built from upstream
`v0.2.2`) leaves dynamically-provisioned buckets without credentials.
In the dynamic-provisioning path, `provisionBucketClaimOperation` sets
`BucketClaim.status.bucketName` but hardcodes `bucketReady=false` and
never re-reads the `Bucket`. The controller does not watch `Bucket`
objects, so the readiness transition the sidecar performs after
`DriverCreateBucket` (`Bucket.status.bucketReady` `false`→`true`) is
never propagated back to the `BucketClaim`. Each periodic resync
re-enters the same branch (`Buckets().Create` returns `AlreadyExists`,
which is ignored) and re-sets `bucketReady=false`. As a result
`BucketClaim.status.bucketReady` stays `false` forever, the sidecar
refuses to grant the `BucketAccess` ("BucketAccess can't be granted to
Bucket not in Ready state"), and the credentials secret is never created
— even though the bucket exists in the backend and the `Bucket` CR
already reports `bucketReady: true`.
This adds a vendored patch that re-reads the live `Bucket` after create
and propagates its readiness onto the `BucketClaim`, so the existing
periodic resync converges the claim to ready and access can be granted.
The fix mirrors what the rewritten upstream controller already does on
`main` (`claim.Status.ReadyToUse = bucket.Status.ReadyToUse`). Upstream
`main` is a `v1alpha2` rewrite and the maintained `release-0.2` branch
still carries the bug, so this stays a vendored patch against `v0.2.2`
until the controller is bumped to a release that includes the fix.
Verified: reproduced the stuck-`false` claim with a unit test against
the upstream `v0.2.2` source and confirmed the patch resolves it,
existing controller tests pass, the patch applies cleanly to `v0.2.2`,
and the controller image builds.
### Release note
```release-note
fix(objectstorage-controller): propagate Bucket readiness to the BucketClaim so dynamically-provisioned buckets receive credentials instead of getting stuck without a granted BucketAccess
```
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Fixed an issue where bucket readiness status was incorrectly reported
when a bucket already existed. The status now accurately reflects the
actual state of the existing bucket instead of being unconditionally set
to not ready.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
|
||
|
|
2363f2d9be |
fix(backups): carry dropdown option sources in CRD annotations, not schema
The four backups.cozystack.io CRDs injected the x-cozystack-options vendor
extension into their OpenAPI validation schema. apiextensions JSONSchemaProps
is a closed struct that only preserves x-kubernetes-* vendor extensions, so
helm-controller's server-side apply rejected the unknown key ("field not
declared in schema") and the CRDs never applied — the controller crash-looped
and backups were non-functional.
Move the field-to-source mapping the dashboard needs into CRD
metadata.annotations (preserved by the apiserver), emitted via
+kubebuilder:metadata:annotations markers, and drop the post-processing awk
injector. The dashboard reattaches the extension client-side.
A helm-unittest suite pins the contract: each dropdown field carries its source
in metadata.annotations and must not carry x-cozystack-options in the schema,
guarding against re-introducing the injector.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
|
||
|
|
b759446fa6 |
feat(monitoring): add tenant overview dashboard
Add a cross-tenant overview dashboard for the root/infra Grafana that surfaces which tenants consume what resources, how many apps (Flux HelmReleases) each runs, and per-tenant health. Panels: - Fleet summary stats (tenants, apps, pods, CPU/mem/storage) - Tenant leaderboard table (CPU/mem usage vs requests, storage, pods, PVCs, app count, not-ready apps) - Top-N bar gauges by CPU, memory, storage and app count - CPU/memory usage trends per tenant - Pod restart rate and not-ready HelmReleases per tenant Registered in dashboards-infra.list so it deploys only to the root/cozy-monitoring Grafana, keeping cross-tenant data off per-tenant instances. Uses standard cadvisor, kube-state-metrics and gotk_resource_info metrics. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com> |
||
|
|
3a5ff3d9c8 |
feat(ouroboros): bump to v0.8.0
v0.8.0 makes the TCP proxy log an explicit reason when its backend readiness check fails, instead of staying silently NotReady. That silent failure mode is exactly what makes a mispointed proxy backend hard to diagnose, so the upgrade pays off the moment the target is wrong. The bump also carries the v0.7.3 migration of the kubectl sidecar image off Docker Hub to mirror.gcr.io, sidestepping anonymous pull rate-limits on shared CI/runner IPs. Chart manifest and controller image are re-pinned by digest in lockstep with the version, and the image-pin test fixture is updated to match. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la> |
||
|
|
f90411da7a |
fix(networking): point host ouroboros proxy at the root-tenant ingress
With publishing.proxyProtocol enabled the host emits a cozystack.ouroboros Package via the no-override Package macro, so the proxy inherits the wrapper chart default backend ingress-nginx-controller.cozy-ingress-nginx. That layout describes a managed Kubernetes tenant cluster; on the host, extra/ingress deploys ingress-nginx into the root tenant namespace as root-ingress-controller in tenant-root. The composed backend FQDN never resolves, so ouroboros-proxy never reaches Ready. Emit the host ouroboros Package with a proxy.target override derived from publishing.ingressName (namespace plus <short>-ingress-controller service name), mirroring the trimPrefix transform extra/ingress applies. Add bundle helm-unittest coverage for the default and a non-default ingress name, and correct the misleading wrapper values.yaml comment. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la> |
||
|
|
588c9f2d62 |
feat(api): add Option resource and x-cozystack-options for dynamic form dropdowns (#2778)
## What this PR does
Adds a generic mechanism for **runtime-populated dropdowns** in
dashboard create/edit forms. Many fields are references to live cluster
resources (GPU device names, KubeVirt instancetypes/preferences, Multus
networks, VM images, bucket storage pools, storage classes, backup
classes/plans) but were free-text or static enums that drift from
reality.
- **`Option` resource** — `core.cozystack.io/v1alpha1`, namespaced,
read-only (list/get/watch). Items are computed on read by an in-process
provider registry using a privileged client, so tenants get curated
option lists without broad cluster reads. Providers: `gpu`,
`instancetype`, `instanceprofile`, `network`, `image`, `storagepool`,
`storageclass`, and backup-related `backupclass`, `plan`, `backup`,
`appkind`.
- **`x-cozystack-options` schema keyword** — app `values.yaml` declare
it via the new cozyvalues-gen `@x-<keyword>` directive (e.g. `##
@x-cozystack-options {source: instancetype}`). Schemas, Go types, and
the `-rd` ApplicationDefinitions are regenerated from source so the
extension is carried into the served OpenAPI. The dashboard renders
annotated fields as dropdowns sourced from the live cluster (UI widget
ships in a separate cozystack-ui PR).
- **RBAC** — the apiserver ServiceAccount gets the privileged reads;
tenants get read-only access to `options` in their namespace via the
aggregated tenant ClusterRoles (granted at `cozy:tenant:view:base`, so
every access level from view upward can populate dropdowns).
- Drops the redundant manual `instanceProfile` enum injection from
vm-instance's Makefile (now driven dynamically).
## Dependency on cozyvalues-gen
The `x-cozystack-options` annotations require the new vendor-extension
directive from cozystack/cozyvalues-gen#27. This PR bumps the pinned
cozyvalues-gen to **v1.6.0**. **A cozyvalues-gen v1.6.0 release must be
cut before CI can pass** — until then the pre-commit schema-generation
job cannot download the binary and will fail.
### Screenshots
N/A — no UI changes in this repository. The consuming dashboard widget
ships in a separate cozystack-ui PR.
### Release note
```release-note
feat(api): add a namespaced read-only Option resource (core.cozystack.io) and the x-cozystack-options schema keyword, enabling dashboard form fields (GPU, instancetype/profile, network, image, storage pool/class, backup class/plan) to render as dropdowns populated from live cluster resources
```
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Expanded dynamic dropdowns across many apps (storageClass,
storagePool, instanceType/instanceProfile, GPU, image, vmdisk, network,
backup/plan/backupclass, appkind) so chart fields can be populated from
live cluster resources.
* **Chores**
* Updated API/RBAC manifests to grant read access needed for option
providers.
* **Tests**
* Added provider and REST tests to validate option sources, scoping,
ordering, and failure handling.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
|
||
|
|
ed20a4322a |
fix(objectstorage-controller): propagate Bucket readiness to BucketClaim
The vendored COSI controller (v0.2.2) sets only BucketClaim.status.bucketName in the dynamic-provisioning path and hardcodes bucketReady=false, never re-reading the Bucket afterwards. The controller does not watch Buckets, so the readiness transition the sidecar performs (false->true) is never reflected on the BucketClaim: bucketReady stays false forever and BucketAccess is never granted, leaving provisioned buckets without credentials. Re-read the live Bucket after create and propagate its readiness, so the periodic resync converges the BucketClaim to ready. This matches the behavior the rewritten upstream controller already has on its main branch. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la> |
||
|
|
26da871c00 |
feat(rbac): allow tenants to start/stop/restart their VMs (#2777)
<img width="2770" height="1970" alt="image" src="https://github.com/user-attachments/assets/774c7c71-0e6a-496a-9898-8ad1ed848b0a" /> ## Summary Grants tenant users permission to call the KubeVirt VM power-control subresources (`subresources.kubevirt.io` → `virtualmachines/{name}/start|stop|restart`, verb `update`) by adding them to the `cozy:tenant:use:base` ClusterRole, which aggregates into `tenant-use`, `tenant-admin`, and `tenant-super-admin`. Without this, the dashboard VM power buttons return 403 even for tenant admins: `kubectl auth can-i update virtualmachines --subresource=start` is `no` for every tenant role today, while `virtualmachineinstances/console|vnc|portforward` are already granted at the same `use` level — so power control belongs there too. ## Companion PR UI that consumes this permission (VM power controls + VNC fixes): cozystack/cozystack-ui#27 ## Test - `helm template` renders `cozy:tenant:use:base` with the new `virtualmachines/start|stop|restart` rule. - After apply, `kubectl auth can-i update virtualmachines --subresource=start|stop|restart` flips from `no` to `yes` for the `tenant-*-use/admin/super-admin` groups. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Virtual Machine Power Control: Users with tenant-level access can now start, stop, and restart virtual machines, providing enhanced management capabilities for VM operations. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
e59f93605a |
test(cozystack-basics): pin tenant view grant on core.cozystack.io options
The tenant view aggregation grants read on the core.cozystack.io/options virtual resource so dashboard dropdowns can be populated. Add a helm-unittest on the cozy:tenant:view:base ClusterRole so a silent RBAC regression on the tenant side is caught, mirroring the apiserver-side rbac test. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la> |
||
|
|
f0f1431546 |
feat(kubernetes): enable GPU passthrough out-of-the-box (NvLinkDisable + gpu=on) (#2780)
## What this PR does Makes GPU passthrough work out-of-the-box for tenant Kubernetes clusters (the `kubernetes` app), so operators no longer have to hand-fix it. Two defaults: 1. **Tenant gpu-operator loads the nvidia driver with `NVreg_NvLinkDisable=1`.** 2. **Nodes in GPU node-groups are labeled `gpu=on` automatically.** ### Root cause (validated empirically on a live cluster) cozystack passes through individual SXM GPUs (e.g. H200) into tenant worker VMs **without** the NVSwitches. Such a GPU's driver then waits for an NVLink fabric that can never come up — there is no NVSwitch and fabricmanager has nothing to manage — so `nvidia-smi` reports `Fabric State: In Progress` indefinitely. As a result every CUDA call fails with `system not yet initialized`, `nvidia-operator-validator` (cuda-validation) crashloops, and no GPUs are advertised. Loading the kernel module with `NVreg_NvLinkDisable=1` flips `Fabric State` to `N/A`, CUDA initializes, and the validators pass. This is the correct setting for per-GPU passthrough because there is no in-VM NVLink/NVSwitch peering — the GPU is alone in the VM, so there is nothing to disable that the workload needs. The second issue: HAMi's `hami-device-plugin` DaemonSet has `nodeSelector: gpu=on` and stays at `DESIRED=0` because GPU worker nodes lack that label, so `nvidia.com/gpu` is never advertised. Labeling the GPU nodes `gpu=on` lets the device plugin schedule and advertise the GPUs. ### How it works - **`gpu=on` label:** node-groups in `packages/apps/kubernetes/templates/cluster.yaml` that declare `gpus` get `--node-labels=gpu=on` appended to their kubelet args (in the `KubeadmConfigTemplate` `joinConfiguration`). Non-GPU node-groups are untouched. - **`NVreg_NvLinkDisable=1`:** the upstream gpu-operator chart only references an existing ConfigMap by name (`driver.kernelModuleConfig.name`) and never creates it. The gpu-operator wrapper chart (`packages/system/gpu-operator`) now renders that ConfigMap (opt-in via `kernelModuleConfig.create`) so it deploys into the tenant `cozy-gpu-operator` namespace alongside the operator. The tenant gpu-operator HelmRelease defaults enable it and point `driver.kernelModuleConfig.name` at it. Both defaults remain overridable: a user setting `addons.gpuOperator.valuesOverride` still wins via the existing `mergeOverwrite(defaults, overrides)` in the HelmRelease template. ### Screenshots Not applicable — no UI changes. ### Release note ```release-note feat(kubernetes): enable GPU passthrough out-of-the-box for tenant clusters. GPU node-groups are now labeled `gpu=on` so HAMi's device plugin schedules and advertises `nvidia.com/gpu`, and the tenant gpu-operator loads the nvidia driver with `NVreg_NvLinkDisable=1` so single-SXM-GPU passthrough (no NVSwitch in the VM) no longer hangs on `Fabric State: In Progress` / `system not yet initialized`. Both defaults are overridable via `addons.gpuOperator.valuesOverride`. ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * GPU-enabled node groups now get the expected GPU label during node registration. * GPU operator supports optional kernel-module parameter configuration with a default parameter set. * **Tests** * Added tests verifying GPU node labeling is applied only for GPU-enabled node groups. * Added tests validating kernel-module config creation, naming, and content behavior. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
b30eb4602d |
fix(cozystack-api): drop unused objectstorage bucketclasses RBAC grant
The Option providers RBAC block granted read on objectstorage.k8s.io/bucketclasses, but no provider in the registry lists BucketClasses and no schema field references a bucketclass source — the bucket app's storage pool field uses the storagepool provider, which reads seaweedfs HelmReleases. Drop the unused grant and pin its absence in the chart test. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la> |
||
|
|
4cbe5b62d1 |
fix(cozystack-api): grant the option apiserver read on plans and backups
The plan and backup option providers list namespaced plans and backups in the backups.cozystack.io group, but the cozystack-api ClusterRole only granted backupclasses there. The apiserver's privileged client runs as this ServiceAccount, so both providers got forbidden — List silently dropped the sources and Get returned 500, leaving the plan/backup dropdowns in the backup forms empty. Add plans and backups to the backups.cozystack.io rule and cover the grant with a chart test. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la> |
||
|
|
34e370e5c5 |
chore(apps): regenerate schemas and ApplicationDefinitions with x-cozystack-options
Regenerate values.schema.json and embedded openAPISchema in the -rd ApplicationDefinitions so the x-cozystack-options dynamic-source directives declared in each app values.yaml are carried into the generated artifacts. Brings the -rd schemas in sync with the hand-edited values.schema.json files (CI runs make generate + git diff --exit-code). Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Andrei Kvapil <andrei.kvapil@aenix.io> |
||
|
|
49976c02cd |
fix(rbac): grant tenant view role read access to options
Options were granted on cozy:tenant:use:base, leaving view-only tenant users (cozy:tenant:view) without read access — so their create/edit forms could not populate dynamic dropdowns. Move the grant down to cozy:tenant:view:base, which aggregates up into use/admin/super-admin, covering every human tenant access level. The tenant ServiceAccount role keeps its grant via cozy:tenant:base. Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Andrei Kvapil <andrei.kvapil@aenix.io> |
||
|
|
d0c74f9b89 |
feat(cozystack-api): add plan, backup and appkind Option sources
Add three dropdown sources to the Option provider registry so the dashboard's backup forms can use the unified x-cozystack-options mechanism instead of injecting client-side enum arrays: - plan / backup: namespaced, list Plans / Backups in the tenant namespace - appkind: cluster-scoped, lists application kinds from ApplicationDefinitions Annotate the backups.cozystack.io CRD schemas (Plan, BackupJob, Backup, RestoreJob) with x-cozystack-options on backupClassName (backupclass), applicationRef.kind / targetApplicationRef.kind (appkind), planRef.name (plan) and backupRef.name (backup). This also gives the previously unused backupclass source its first consumer. Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Andrei Kvapil <andrei.kvapil@aenix.io> |
||
|
|
ec6ec76703 |
feat(cozystack-api): add Option resource for dynamic form dropdowns
Introduce a read-only, namespaced virtual resource core.cozystack.io/v1alpha1 Option that serves named lists of dropdown options for the dashboard. Each object (one per source: gpu, instancetype, instanceprofile, network, image, storagepool, storageclass, vmdisk, backupclass) is computed on read by an in-process provider using a privileged dynamic client, so tenants need no direct access to Nodes, the KubeVirt CR, cluster instancetypes, etc. Tenants get read access via the aggregated cozy:tenant roles; the apiserver ServiceAccount gains read on the underlying sources. Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Andrei Kvapil <andrei.kvapil@aenix.io> |
||
|
|
a60c2e6e68 |
fix(gpu-operator): name kernel-module ConfigMap after the driver reference
The wrapper chart named the kernel-module ConfigMap from its own kernelModuleConfig.name key, while the NVIDIA driver mounts the ConfigMap referenced by gpu-operator.driver.kernelModuleConfig.name. The two keys defaulted to the same value but were never linked, so overriding only the driver reference left the driver pointing at a ConfigMap that is never rendered and the NVreg_NvLinkDisable=1 parameters were silently dropped. Derive the ConfigMap name from the driver's effective reference, falling back to the wrapper key when unset, so the rendered ConfigMap and the driver reference can no longer diverge. Add helm-unittest coverage for the rendered name, namespace, data key, and the create=false no-op. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la> |
||
|
|
c435efa199 |
feat(flux): upgrade to v2.8.0 + chart fixes for strict SSA & kstatus (folds #2612) (#2602)
## What this PR does Upgrades Flux v2.7.3 → v2.8.0 across both the vendored tenant chart and the embedded management-cluster manifests, and folds in the chart fixes that become hard errors under the new strict helm-controller v1.5. Flux v2.8's helm-controller v1.5.0 ships: - **Server-Side Apply with `--force-conflicts`** — strict CRD schema enforcement; misplaced fields (silently dropped on v2.7) now fail the apply. - **kstatus-based health checking** by default — parent HR waits for every applied resource (including child HRs) to be Ready before flipping its own Ready, surfacing latent ordering deadlocks. - **Helm v4 embedded** — `upgrade.force: true` is deprecated and now conflicts with SSA. - **`HelmRelease.spec.healthCheckExprs`** — prerequisite for proper readiness gating (used in PR #2601 split). Folds in PR #2612 (kubevirt-instancetypes null TPM fix) since the same Flux upgrade triggers it. ## Commits **Flux upgrade itself:** - `feat(fluxcd)`: bump `flux-operator` / `flux-instance` vendored charts to v0.48.0; web UI opt-in. - `feat(flux)`: regenerate embedded management-cluster manifests via `make update` in `packages/core/flux-aio` (timoni bundle build). **Chart fixes for strict SSA — fields the chart sent that v2.7 silently dropped, v2.8 rejects:** - `fix(kubevirt-instancetypes)`: drop persistent strip that produced null `preferredTPM` (folds #2612). - `fix(foundationdb)`: relocate `faultDomain`, `imageType`, `labels`, `minimumUptimeSecondsForBounce` from inside `automationOptions` to direct children of `spec`. - `fix(kafka)`: place `enableServiceLinks` under `template.pod`, not a phantom `template.spec`. - `fix(vm-instance)`: emit `disk: {}` (not `disk:`/null) when no bus is set. - `fix(platform)`: drop deprecated `upgrade.force: true` from HelmReleases; fix `kafka` WorkloadMonitor `replicas` paths. **Ordering / deadlock fixes under v2.8 kstatus:** - `fix(vpa)`: break circular wait between parent install and nested `vpa-for-vpa` HR. - `fix(kubernetes)`: drop lookup-guarded parent-HR `dependsOn` on tenant addon child HRs (parent waits on child via kstatus, child waited on parent — deadlock). **E2E waits for v2.8 kstatus timing:** - `test(e2e)`: bump app HR-Ready waits to 5m (was 20s–100s under v2.7's faster dispatch). - `test(e2e)`: wait for parent HR Ready before downstream asserts in `run-kubernetes.sh` and `vminstance.bats`. ## Scope discipline This PR is part of the split of #2619 (the consolidated CI fixes branch) into review-friendly pieces. Companion PRs: - **PR #2601** (seaweedfs split) — folded into this PR (commits `29c6afc8`, `0e8b46d7`, `7157158c`, `dccdeb52`, `f880b324`): the seaweedfs-system → seaweedfs-db + seaweedfs-system split, its adoption migration 43 (targetVersion 44), and the configurable db resources all land here, because the strict-SSA `upgrade.force` removal and the kstatus parent-HR timeout bump only make sense together with the split. #2601 is superseded. - **PR #2558** (drop 3× retry on `Run E2E` + `Install Cozystack`) — independent, lands separately. - Several smaller standalone fixes lifted out of #2619 (startup probes, cert-manager `dependsOn`, prepull machinery, CSI HR timeout, NFS/OIDC test improvements) — opened as separate PRs. ## Verification - `helm template` renders cleanly for both `fluxcd` and `fluxcd-operator` packages with `web.enabled=false` (default) and `web.enabled=true`. - Embedded `cmd/cozystack-operator` binary contains the v1.5.0 / v1.8.0 / v2.1.0 controller image strings. - No references to the v0.39-removed `--disable-wait-interruption` flag anywhere in `packages/` or `internal/`. ### Release note ```release-note Flux upgraded to v2.8.0 (helm-controller v1.5 — Helm v4 Server-Side Apply with --force-conflicts, kstatus health checking). When upgrading existing clusters: - Kubernetes 1.33+ is now required for the platform (management) cluster, and for any tenant cluster that enables the optional (default-off) Flux addon — that addon ships the bumped Flux too. - HelmReleases no longer set `upgrade.force: true`. Helm v4 SSA resolves field-ownership conflicts automatically (`--force-conflicts`), but that is not the old client-side replace: immutable-field changes (e.g. StatefulSet volumeClaimTemplates/serviceName) no longer self-heal and require manual recreation — delete the object (e.g. `kubectl delete sts <name> --cascade=orphan`) and let Flux recreate it. - KubeVirt: persistent TPM/EFI is re-enabled for the Windows 11/2k22/2k25 preferences (KubeVirt 1.8 VMPersistentState); each affected VM provisions an extra RWO backend-storage PVC from the default StorageClass. - KubeVirt: the EOL centos.7*/centos.stream8* preferences are retained as deprecated, hidden aliases (`tags: hidden`, `instancetype.kubevirt.io/deprecated: "true"`) — existing VMInstances on these profiles keep rendering and need no action on upgrade, but the profiles are no longer offered for new VMs; repoint to centos.stream9/10 when convenient. The gn1.* GPU instancetypes are likewise retained. - FoundationDB: imageType now reaches the operator (silently dropped pre-SSA); it is pinned to `split` to match the value existing clusters effectively ran, so upgrades stay non-disruptive. Set `imageType: unified` to migrate deliberately. ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Flux Status web UI: optional web server, config secret, service port, HTTPRoute/Ingress, network policy, and RBAC roles. * New SeaweedFS DB Helm chart and optional managed DB release. * **Improvements** * CRD/schema enhancements: new provider kinds, validations, variant option, and external checksum refs. * Raised Kubernetes prerequisite to 1.30+; extended e2e timeouts for reliability. * **Chores** * Bumped Flux Operator and Flux versions; documentation links updated to fluxoperator.dev. * **Bug Fixes** * Removed aggressive HelmRelease force-upgrade/install flags. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/cozystack/cozystack/pull/2602?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
2d58479f06 |
feat(platform): add kuberture as optional system package (#2647)
<!-- Thank you for making a contribution! Here are some tips for you: - Use Conventional Commits for the PR title: `type(scope): description` - Types: feat, fix, docs, style, refactor, perf, test, build, ci, chore - Scopes are not an exhaustive list — pick the most specific scope for the change and extend the list when a genuinely new area appears. Examples: - System components: dashboard, platform, operator, cilium, kube-ovn, linstor, fluxcd, cluster-api - Managed apps: postgres, mariadb, redis, kafka, clickhouse, virtual-machine, kubernetes - Development and maintenance: api, hack, tests, ci, docs, maintenance - Breaking changes: append `!` after type/scope (`feat(api)!: ...`) or add a `BREAKING CHANGE:` footer - If it's a work in progress, consider creating this PR as a draft. - Don't hesistate to ask for opinion and review in the community chats, even if it's still a draft. - Add the label `backport` if it's a bugfix that needs to be backported to a previous version. --> ## What this PR does Adds [kuberture](https://github.com/lexfrei/kuberture) as an optional system package. Kuberture is a small controller that translates the `default/kubernetes` EndpointSlice into headless Services with external-dns-style annotations, closing the gap that external-dns cannot use EndpointSlice as a source directly: ```text EndpointSlice (kubernetes) → kuberture → headless Service(s) with annotations → external-dns → DNS ``` The package is opt-in via `bundles.enabledPackages: [cozystack.kuberture]`. Operators populate `config.outputs` per HelmRelease — each output targets a specific external-dns instance by its `annotationPrefix`, so a single kuberture install can serve multiple external-dns instances (e.g. one publishing to the public zone, another to an internal corporate prefix) simultaneously. The vendored chart at `packages/system/kuberture/charts/kuberture/` is pulled from `oci://ghcr.io/lexfrei/kuberture/charts/kuberture` and pinned by both version AND OCI manifest digest in the Makefile (mirroring the ouroboros lockstep pattern). The controller image at `ghcr.io/lexfrei/kuberture` is pinned by tag+sha256 in the shim values.yaml. Both pins advance in lockstep with each upstream release; the procedure is documented inline. Install-order dependencies declared in `PackageSource`: `cozystack.networking` (CNI before pod scheduling) and `cozystack.prometheus-operator-crds` (ServiceMonitor CRD before the chart's enabled-by-default ServiceMonitor manifest). External-dns is deliberately NOT a dependency — kuberture creates annotated Services regardless of whether external-dns is installed; external-dns is a downstream consumer, not a runtime prerequisite. Coverage: - **helm-unittest** (`packages/system/kuberture/tests/kuberture_test.yaml`, 10 cases): fail-fast on empty outputs, ServiceMonitor enabled by default, source pinned to `default/kubernetes`, multi-output prefix isolation, empty-string `annotationPrefix` schema rejection, omitted-prefix fallback to controller default, ConfigMap → Deployment volume mount, controller image pinned by tag+sha256 digest, Role permits full Service lifecycle, metrics containerPort derived from `metricsBindAddress`. - **bats e2e** (`hack/e2e-apps/kuberture.bats`): applies a `Package cozystack.kuberture` with two outputs (different `annotationPrefix` values), waits for HelmRelease and controller readiness, asserts both output Services are headless and carry the right `hostname`/`target`/`ttl` annotations under their configured prefix, cross-checks per-output isolation (each Service only carries its own prefix's annotations). ### Screenshots <!-- REQUIRED for UI changes: attach screenshots or screen recordings demonstrating the visual impact of your changes. PRs with UI changes without screenshots will not be merged. --> Not applicable — no UI changes. ### Release note <!-- Write a release note: - Explain what has changed internally and for users. - Start with the same `type(scope):` prefix as in the PR title - Follow the guidelines at https://github.com/kubernetes/community/blob/master/contributors/guide/release-notes.md. --> ```release-note feat(platform): add kuberture as an optional system package — translates the default/kubernetes EndpointSlice into annotated headless Services so external-dns can publish the Kubernetes API endpoint to DNS. Opt-in via bundles.enabledPackages: [cozystack.kuberture]; populate config.outputs to target one or more external-dns instances by annotationPrefix. ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Adds kuberture as an optional system package to publish the Kubernetes API endpoint to DNS via configurable external-dns outputs; includes Helm chart, RBAC, NetworkPolicy, PDB, ServiceMonitor, and validated chart values/schema. * **Tests** * Adds Helm unit tests and an end-to-end smoke test validating controller readiness, headless Service annotations, and external-dns routing/probe behavior. * **Documentation** * Adds a full README with usage, configuration examples, and vendoring/pinning guidance. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/cozystack/cozystack/pull/2647) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai --> --- Documentation companion: [cozystack/website#539](https://github.com/cozystack/website/pull/539). |
||
|
|
238a3b665c |
feat(kubernetes): default NVreg_NvLinkDisable=1 for tenant gpu-operator
When a single SXM GPU (e.g. H200) is passed through into a tenant worker VM without the NVSwitches, the nvidia driver waits forever for an NVLink fabric that can never come up (Fabric State: In Progress). Every CUDA call then fails with 'system not yet initialized' and the nvidia-operator-validator crashloops. Loading the kernel module with NVreg_NvLinkDisable=1 flips Fabric State to N/A so CUDA initializes — correct for per-GPU passthrough, which has no in-VM NVLink/NVSwitch peering anyway. The upstream gpu-operator chart only references an existing ConfigMap by name via driver.kernelModuleConfig.name and never creates it. Render that ConfigMap from the gpu-operator wrapper chart (opt-in via kernelModuleConfig.create) so it lands in the tenant cozy-gpu-operator namespace alongside the operator, and wire the tenant HelmRelease defaults to enable it and point the driver at it. Remains overridable via addons.gpuOperator.valuesOverride. Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Andrei Kvapil <andrei.kvapil@aenix.io> |
||
|
|
8e78add8ea |
feat(rbac): allow tenants to start/stop/restart their VMs
Grant the subresources.kubevirt.io virtualmachines/start|stop|restart "update" verb in cozy:tenant:use:base so the dashboard VM power controls work for tenant users (aggregates into admin/super-admin). Without it the actions return 403 even for tenant admins. Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Andrei Kvapil <andrei.kvapil@aenix.io> |
||
|
|
d2bc261897 |
chore(metallb): bump to v0.16.1 and rotate host-network port denylist (#2699)
## What this PR does Bump vendored MetalLB chart from v0.15.2 to v0.16.1 and rebuild the cozystack-built `metallb-controller` / `metallb-speaker` images at the new version. Adopt the upstream-default BGP backend: FRR-K8s replaces the deprecated FRR mode. Rotate the cilium-networkpolicy clusterwide host-network port denylist to match the v0.16 listener set. The chart introduces a new probe contract (`/healthz` and `/readyz` on a dedicated host-local port 17472, distinct from the metrics port), so the cozystack-built controller and speaker images must move in lockstep with the chart. Leaving the digests on v0.15.2 would CrashLoopBackOff every pod on main between merge and the next release-prep commit. Upstream highlights between 0.15.2 and 0.16.1: - 0.16.0: FRR-K8s is the new default BGP backend; legacy FRR is deprecated. - 0.16.0: kube-rbac-proxy replaced by native TLS; metrics are HTTPS-only on the formerly-rbac-proxy port 9120. Default TLS minimum is now 1.3 (was 1.2); operators with TLS 1.2 scrapers override via `metallb.tls.minVersion: VersionTLS12`. - 0.16.0: new `tls.*` and `networkpolicies.*` value blocks (opt-in). - 0.16.1: chart-only patch — liveness/readiness probe port is now a configurable value (default unchanged at 17472), controller probes drop the hardcoded `host: 127.0.0.1`, pods/ServiceMonitor/PodMonitor gain `prometheus.io/scheme: https`, the frr-k8s subchart gains an opt-in ServiceMonitor toggle (default off), and one CRD numeric field widens from int32 to int64. - 0.15.3: `ConfigurationState` CRD exposes reconcile errors per component; chart gained NetworkPolicy support and tightened pod SecurityContext. The `packages/system/metallb/values.yaml` header documents the changes operators see on upgrade, including the partial nature of the legacy-FRR escape hatch (Helm evaluates dep `condition:` against the declaring chart's values context, so a grandparent override from the umbrella cannot suppress the frr-k8s subchart through that condition; the subchart stays installed but idle when the speaker is flipped to FRR mode). New helm-unittest coverage pins the post-bump invariants and would have caught the original chart/binary skew before merge: controller/speaker image tags exactly match the chart `appVersion`, speaker is the single-container DaemonSet with `BGP_TYPE=frr-k8s`, frr-k8s DaemonSet and CRDs are installed, NetworkPolicies stay off by default. The cilium-networkpolicy chart gains its first unittest suite, enumerating every metallb v0.16 host-network port plus the unrelated etcd kube-rbac-proxy port that shares port number 9443 (pod-IP vs host-network). ### Release note ```release-note chore(metallb): bump MetalLB to v0.16.1; adopt upstream-default FRR-K8s BGP backend in place of the deprecated FRR mode. Metrics endpoints move from HTTP on 7472 to HTTPS on 9120 with native TLS 1.3 by default (operators on TLS 1.2 scrapers must set `metallb.tls.minVersion: VersionTLS12`). The cilium-networkpolicy clusterwide host-network port denylist is rotated to cover the new metallb listeners (7946 memberlist, 9120, 9121, 9140, 9141, 19443). The legacy FRR mode remains available via `metallb.frrk8s.enabled=false` + `metallb.speaker.frr.enabled=true`, with the caveat that the frr-k8s subchart stays installed (idle) under that escape hatch. ``` |
||
|
|
27edd73bca |
fix(kubevirt-instancetypes): retain EOL centos preferences as deprecated aliases
Address review feedback from lexfrei: dropping the centos.7/centos.7.desktop/
centos.stream8{,.desktop,.dpdk} VirtualMachineClusterPreference objects hard-fails
the vm-instance Helm render (vm.yaml fails when a referenced preference is absent)
and makes the dynamic CRD enum reject the stored value for every existing VM on
those profiles on upgrade. Re-add them as deprecated aliases in
extra-instancetypes.yaml, mirroring the gn1.* GPU instancetype treatment, and
extend the vm-instance enum generation to union preference names from
extra-instancetypes.yaml so the retained profiles stay in values.schema.json and
the RD schema.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
|
||
|
|
fd59dea234 |
feat(fluxcd): bump flux-operator/flux-instance charts to v0.50.0
Re-pull the vendored flux-operator and flux-instance charts from 0.48.0 to the latest v0.50.0 (operator-version bumps only: OpenShift v4.21 compat, OLM base image, Kubernetes client deps — no Flux distribution change). The kubernetesEnvs and networkPolicy patches re-apply cleanly. distribution.version stays 2.8.x, so the tenant Flux toolkit auto-tracks the latest 2.8 patch (currently 2.8.8) at reconcile. The management flux-aio module is already at its latest published build (2.8.0); no newer 2.8.x module exists upstream yet. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com> |
||
|
|
57c0ce66bc |
test: cover flux v2.8 chart fixes and wire missing test targets
- kafka: assert WorkloadMonitor reads .Values.kafka.replicas / .Values.zookeeper.replicas (regression for the phantom .Values.replicas), and that enableServiceLinks lives under entityOperator.template.pod. - tenant: pin that no swept HelmRelease carries upgrade.force (would have caught the missed gateway.yaml). - seaweedfs-db: baseline render cover for the new split-out chart. - kafka and seaweedfs-db had no `test` Makefile target, so their suites never ran in CI; add one to each. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com> |
||
|
|
9cda93d710 |
fix(kubevirt-instancetypes): pin common-instancetypes and retain gn1 GPU types
Building from unpinned common-instancetypes HEAD on every `make update` silently churns the catalog. Worse, the v1.3.0 upstream removal dropped the gn1.* (GPU NVIDIA) instancetypes that existing GPU VMs and tenant Kubernetes GPU workers still reference — vm-instance/templates/vm.yaml hard-fails the render when a referenced instancetype is absent. Pin the source to a commit SHA (not a tag: the multi-arch preferredArchitecture fields exist only on main past v1.6.0, so a tag would regress them) and re-append the gn1.* objects from a Cozystack-local extra-instancetypes.yaml the regen copies into templates/. The EOL centos.7*/centos.stream8* preferences stay dropped (release-noted). Regenerate the vm-instance and kubernetes README instancetype/preference tables to match the shipped catalog. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com> |