mirror of
https://github.com/cozystack/cozystack.git
synced 2026-11-08 13:04:53 +09:00
2a78e7b2475ecffe3ddbcac7869cd7bcc567f562
155
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
d30a2cfffb |
docs+test(apps/kubernetes): align nodeGroups default docs with actual zero-worker topology + regression-guard the replicas fix
Follow-ups from the self-review of #3233: - `values.yaml` / helper docstring / regenerated README + schema + cozyrds openAPISchema + Go type doc: the previous "one ingress-nginx worker" contract was already misleading (helper default carried `minReplicas: 0` but the chart hardcoded `spec.replicas: 2`), and the replicas fix makes the docstring strictly false — an empty-nodeGroups install now provisions zero workers until either the cluster-autoscaler responds to an unschedulable Pod or the operator explicitly scales the group. Update the docstrings to describe the actual behaviour and to spell out the ingress-nginx-addon implication so operators are not surprised at addon-install time. - `tests/nodegroups_default_test.yaml`: two regression cases pinning `MachineDeployment.spec.replicas == $group.minReplicas` for `minReplicas: 0` (the render-side OIDC bats path — zero worker DataVolumes provisioned) and for `minReplicas: 2` (the kubernetes-latest / kubernetes-previous bats path — byte- identical to pre-PR behaviour). Without these a future refactor can silently re-hardcode `replicas: 2` and turn no tests red. helm-unittest suite grows from 171 to 173, both new cases pass. Ref: cozystack/cozystack#3231. Signed-off-by: IvanHunters <xorokhotnikov@gmail.com> |
||
|
|
7b65cf2afd |
feat(platform): migrate to etcd-operator v1alpha2 (#2859)
<!-- 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 ### 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. --> ### 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 ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added support for the newer etcd snapshot workflow (BackupClass/BackupJob/RestoreJob) with in-place restore. * Updated etcd chart/operator packaging and migration flow for the v1alpha2 operator release. * **Bug Fixes** * Switched readiness/condition handling to **Available**. * Improved waits to cover all etcd member pods during restore and scenario steps. * **Documentation** * Refreshed etcd backup/restore docs and example scenarios to match the v1alpha2 APIs and parameters. * **Tests** * Updated e2e coverage to validate v1alpha2 operator runtime contracts and replaced legacy backup-block tests with a snapshot round-trip test. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
cc5d688e15 |
feat(platform): migrate to etcd-operator v1alpha2
Signed-off-by: Andrey Kolkov <androndo@gmail.com> |
||
|
|
7b8a330ad4 |
docs(apps/kubernetes): update users[].email docstring — email claim, not preferred_username
Gemini flagged that the `values.yaml` @field docstring on `oidc.users[].email` still described the claim mapping as `preferred_username`, misleading operators after the claim was switched to `email` for real (see the earlier fix and its end-to-end verification on dev3). Rewrite the description to match the actual mechanic: `email` claim, requested via `--oidc-extra-scope=email` in the chart-generated kubeconfig, emitted by every conformant OIDC provider. `make generate` re-propagates the update through README.md, types.go and the cozyrds embedded schema. Note on the other finding in the same review — Gemini also flagged `audiences` as being incorrectly nested under `issuer` in the AuthenticationConfiguration Secret. That is a false positive: per the kube-apiserver v1beta1 spec (apiserver.config.k8s.io/v1beta1, `JWTAuthenticator.Issuer`), `audiences` IS a child of `issuer`, not a sibling of `jwt[i]`. The current shape is correct and verified end-to-end on dev3 (alice/bob tokens carry `aud: [tenant-test-kubernetes-test3, kubernetes]` and apiserver validates them successfully with CRB-driven RBAC). Signed-off-by: Ivan Okhotnikov <ivan.okhotnikov@aenix.io> |
||
|
|
9c73b6ef10 |
fix(apps/kubernetes): render-fail when spec.oidc.mode collides with legacy --oidc-* extraArgs
Reviewer flagged a real customer-upgrade regression: the previous values.yaml docstring on `controlPlane.apiServer.extraArgs` documented `--oidc-issuer-url`/`--oidc-client-id` as a valid usage. An existing customer who wired OIDC by hand through that passthrough (following the doc) would see their tenant kube-apiserver BOOT-FAIL the moment they toggle `spec.oidc.mode` to `System` or `CustomConfig`: kube-apiserver refuses to boot with both `--authentication-config` (injected by the new spec.oidc) and any legacy `--oidc-*` flag — `--authentication-config cannot be used with any of --oidc-*`. Add a render-time guard: when `spec.oidc.mode != None`, scan the user-supplied `controlPlane.apiServer.extraArgs` for any flag with prefix `--oidc-` and fail with a clear message pointing at the `spec.oidc.mode: CustomConfig` migration path (they can carry the same issuer/audience inside `customConfig.config`). When `spec.oidc.mode: None` the passthrough still works — customers who manage OIDC entirely by hand keep working until they opt into the new selector explicitly. Also update the values.yaml docstring on `extraArgs` to steer OIDC users to `spec.oidc.mode` and warn against the collision. Two new helm-unittest cases: the collision fails, and mode=None with legacy flags renders normally (backward compat). Signed-off-by: Ivan Okhotnikov <ivan.okhotnikov@aenix.io> |
||
|
|
5950450758 |
feat(apps/kubernetes): add Kubernetes.spec.oidc selector API
Introduce a flat selector — `mode: System | CustomConfig | None` — plus a `users[]` list and a `customConfig` block for tenant-supplied AuthenticationConfiguration. Default `None` preserves today's behavior. The `System` mode trusts the platform `cozy` realm via a per-cluster public client; `CustomConfig` accepts an inline `AuthenticationConfiguration` or a Secret reference (mutually exclusive). The `users[]` list drives per-user ClusterRoleBindings inside the tenant cluster, with two roles: `admin` and `view`. Regenerates deepcopy, JSON schema, README, and the kubernetes-rd cozyrds embedded schema. Implements Phase 1 API of the per-tenant OIDC design proposal (cozystack/community#24). Signed-off-by: Ivan Okhotnikov <ivan.okhotnikov@aenix.io> |
||
|
|
22c96d8dac |
fix(kubernetes): default worker disk storageClass to the application storageClass
Worker node VMs set evictionStrategy: External, so they live-migrate. Live migration requires the system DataVolume on a ReadWriteMany volume, and linstor-csi only grants RWX on a DRBD-backed StorageClass. When a node group leaves storageClass empty the template previously omitted the field and fell through to the management cluster default StorageClass, which may be a non-DRBD class the CSI driver rejects for RWX — breaking migration. Fall back to the application-level storageClass (the replicated/DRBD class) when the node group storageClass is empty, instead of the cluster default. When both are empty the field is still omitted, preserving the explicit cluster-default opt-out. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la> |
||
|
|
3e20a0cd41 |
fix(kubernetes): make node group resources optional when instanceType is set (#3121)
## What this PR does
A tenant Kubernetes node group can be sized two ways: by `instanceType`
or by an explicit `resources` block. The generated values schema,
however, marked `resources` as required on every node group, so a node
group sized purely by `instanceType` was rejected at install time:
```text
at '/nodeGroups/<name>': missing property 'resources'
```
The same failure occurs through the typed `Kubernetes` CR: an empty
`resources: {}` is dropped during the CR-to-HelmRelease translation, so
by validation time the key is absent and the required check fails — even
though sizing was already fully specified by `instanceType`.
This marks `resources` optional in the node group definition and
regenerates the dependent artifacts (`values.schema.json`, API types,
README, and the `ApplicationDefinition`). No change is needed to emit
the VM: the chart already renders `domain.cpu`/`domain.memory` only when
`resources` is present and `instancetype` only when set, so a node group
sized purely by `instanceType` now validates and installs. Node groups
that specify `resources` are unaffected.
`instanceType` and `resources` are alternative, mutually exclusive
sizing sources — KubeVirt rejects a VirtualMachine that references an
instancetype and also sets explicit `domain.cpu`/`domain.memory`, since
instancetype CPU/memory cannot be overridden. To avoid emitting a VM
that the instancetype admission webhook would later reject, the chart
now fails fast at render time with a clear message when a node group
sets both a non-empty `instanceType` and explicit `resources`.
Tests: helm-unittest coverage proves a node group with `instanceType`
and no `resources` passes schema validation and renders without explicit
`domain.cpu`/`memory`; a complementary case confirms explicit
`resources` are still honoured; and a `failedTemplate` case pins the
render-time rejection of the conflicting both-set combination. The
omit-resources case fails against the pre-fix schema with the exact
error above, so it is a real regression guard.
Addresses #3046.
### Screenshots
N/A — schema and chart change, no UI impact.
### Release note
```release-note
fix(kubernetes): allow a node group to omit `resources` when it is sized by `instanceType` (previously failed schema validation with "missing property 'resources'"); reject the unsupported combination of `instanceType` and explicit `resources` at render time
```
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Worker node groups can optionally size CPU/memory via `resources`, and
can omit `resources` when using `instanceType`.
* **Bug Fixes**
* Render now validates CPU/memory rules: `instanceType` with only one of
`resources.cpu`/`resources.memory` fails, and `instancetype` is omitted
when both `resources.cpu` and `resources.memory` are set (with
`instanceType` ignored).
* **Documentation**
* Updated API/Helm docs and JSON schema to clarify `resources` vs
`instanceType` precedence and the “set both CPU and memory (or neither)”
requirement.
* **Tests**
* Added helm-unittest scenarios covering omission, precedence, and
render-time failure cases.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
|
||
|
|
bf14a73b39 |
feat(api): add SecurityGroup network policy resource (sdn.cozystack.io) (#2922)
## What this PR does
Introduces a tenant-facing `SecurityGroup` resource in a new
`sdn.cozystack.io/v1alpha1` API group, served by the Cozystack
aggregated API server as a 1:1 projection of a `CiliumNetworkPolicy`. A
SecurityGroup attaches to one of the tenant's managed applications by
reference (`spec.targetRef: {apiGroup, kind, name}`) and declares
allow-list ingress/egress for that application. Tenants manage network
policy for their own apps entirely through
`securitygroups.sdn.cozystack.io`, without being granted any access to
the `cilium.io` API group.
The translation is synchronous and stateless — the API server converts
each SecurityGroup into a CiliumNetworkPolicy in the same namespace on
write and back on read; there is no controller. The backing policy's
`endpointSelector` is **derived** from `targetRef` (matched on the
application's lineage labels
`apps.cozystack.io/application.{group,kind,name}`), never copied from
tenant input, so the selector is machine-generated and can only ever
match the referenced application's own pods in the tenant's namespace.
Policies owned by this API carry an `sdn.cozystack.io/securitygroup`
marker label that the storage always re-asserts and hides from the view,
so it only ever surfaces or mutates its own policies and never touches
platform-managed network policies.
The value is self-service network policy on a Cozystack-native,
RBAC-scoped surface, without exposing Cilium's version-coupled CRDs to
tenants. Because the selector is derived from an authorized application
reference rather than free-form tenant input, the RBAC boundary is
structural, not selector-validated: a tenant cannot express network
policy against arbitrary or platform-owned pods. The full design —
selector derivation from lineage labels, the structural boundary, the
additive-policy reality (a SecurityGroup widens a managed application's
allowed traffic but cannot sever its platform-managed management plane,
and equally cannot tighten below the platform baseline), the in-tree
CiliumNetworkPolicy mirror that avoids a Cilium Go-module dependency,
RBAC, and deferred extensions (raw-pod targeting, cluster scope,
reusable groups) — is in `pkg/apis/sdn/DESIGN.md`.
Implements the attachment model from #1614.
### Release note
```release-note
feat(api): add the SecurityGroup resource (sdn.cozystack.io/v1alpha1) — a tenant-facing, namespace-scoped firewall that attaches to a managed application by reference and projects 1:1 onto a CiliumNetworkPolicy with a machine-derived endpoint selector, letting tenants manage their application's network policy without cilium.io access.
```
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added the `SecurityGroup` API resource (`sdn.cozystack.io` v1alpha1)
with a namespaced projection backed by Cilium network policies.
* Enabled the SDN `APIService` and wired SDN routing, scheme, and REST
support.
* Expanded RBAC to include SecurityGroup access and required Cilium
policy permissions.
* **Documentation**
* Added a design document describing projection behavior and rule
semantics.
* **Bug Fixes**
* Improved API rule validation coverage for missing list-type fields.
* **Tests**
* Added SDN round-trip, fuzzing, RBAC, and comprehensive REST
create/get/list/update/delete/watch/resource-version tests.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
|
||
|
|
a349c753ad |
fix(kubernetes): make node group resources optional and prefer them over instanceType
A node group is sized either by instanceType or by explicit resources, but the generated values schema required resources on every node group. A node group with instanceType and no resources — or an empty resources dropped during typed-CR to HelmRelease translation — failed schema validation with "missing property 'resources'" even though sizing was fully specified. Mark resources optional in the node group definition and regenerate the schema, API types, README, and ApplicationDefinition. The chart template emits domain.cpu/memory only when resources is present, so a node group sized purely by instanceType now passes validation and installs. When a node group sets both instanceType and explicit resources, explicit resources take precedence: the instancetype is omitted from the rendered VM and the per-group instancetype lookup is skipped, so KubeVirt accepts the explicit domain.cpu/memory with no instancetype to conflict with. instanceType stays required and defaulted (no schema change), so the console's required instanceType dropdown keeps working — sending the default instanceType plus explicit resources simply sizes the VM by resources. This replaces an earlier render-time hard failure on the both-set case, which was unreachable to clear from the dashboard (the required dropdown cannot be emptied). Explicit resources are all-or-nothing alongside an instanceType: a partial spec (only cpu, or only memory) on a group that carries a non-empty instanceType would emit one domain override next to the instancetype — which KubeVirt rejects — so it now fails at render time with a clear error. Partial resources on a group without an instanceType (used to tune kubelet reservations) are unaffected. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la> |
||
|
|
31c15b282f |
feat(network): mechanism-agnostic LoadBalancer exposure (ExposureClass + ServiceExposure) (#3081)
## What this PR does Lays the foundation for migrating tenant LoadBalancer exposure off the deprecated `Service.spec.externalIPs` (KEP-5707) and, eventually, off MetalLB onto Cilium-native announcement — the mechanism-agnostic shape prescribed when the earlier chart-side approach (#2468) was reverted in #2603. It adds a new `network.cozystack.io/v1alpha1` API group and a controller that translates intent into whichever LoadBalancer backend the cluster admin configured: - `ExposureClass` (cluster-scoped, admin): binds a logical class name to a backend (`externalIPs` | `metallb` | `cilium` | `robotlb`) and its VIP address scope — the StorageClass/IngressClass pattern. - `ServiceExposure` (namespaced, tenant intent): "expose this Service via class X"; status reports the resolved backend and assigned IPs. - A `serviceexposure` controller renders the backend's pool + announcer once per class (MetalLB `IPAddressPool` + `L2Advertisement`; Cilium `CiliumLoadBalancerIPPool` + `CiliumL2AnnouncementPolicy`), scoped to the namespaces that opted in. Backends are pluggable behind a small Go interface, so adding BGP or another cloud LB is one implementation, not an API change. The controller never mutates the target Service — the chart still owns its shape. Platform wiring: `publishing.exposureClass.*` renders the admin `ExposureClass` and the host ingress publishes through it. The default (no class set, `externalIPs`) leaves every existing cluster's behaviour byte-for-byte unchanged; the MetalLB→Cilium announcer migration becomes a single `ExposureClass.spec.backend` change. This is the foundation only — Part of #2586. Converting per-app exposure, flipping Cilium `l2announcements` on, changing the default, and removing MetalLB are deferred to later phases. ### Release note ```release-note feat(network): add ExposureClass and ServiceExposure for mechanism-agnostic LoadBalancer exposure. Opt-in foundation; the default externalIPs publishing path is unchanged. ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added new `ExposureClass` and `ServiceExposure` custom resources with support for multiple backends (externalIPs, MetalLB, Cilium, RobotLB), including optional L2 and address configuration. * Added Helm wiring and templates to enable service/ingress publishing via `ServiceExposure`, selecting a configured (or default) `ExposureClass`. * **Bug Fixes** * Improved reconciliation, finalizer-based cleanup, and status updates for readiness and assigned IP reporting, including safer handling when backends or managed resources change. * **Tests** * Added end-to-end and unit test coverage for backend rendering, readiness, and cleanup flows. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
7e3c5f99db |
fix(kubernetes): apply default md0 node group only when nodeGroups is empty
The chart shipped a default nodeGroups.md0 in values.yaml. Helm deep-merges
values, so the default md0 was re-added on top of any user-supplied
nodeGroups; combined with Kubernetes stripping null values, md0 could never
be removed by configuration. Move the default into the template
("kubernetes.nodeGroups" helper) so it is applied only when nodeGroups is
empty. User-supplied node groups now fully replace the default, letting users
name and omit groups (including md0) freely.
Test fixtures that relied on the chart-default md0 to supply diskSize via
values merge now set it explicitly.
Signed-off-by: mattia-eleuteri <mattia@hidora.io>
|
||
|
|
243ce65071 |
feat(kubernetes): expose tenant apiserver authentication in app values
Tenant Kubernetes clusters had no way to configure the kube-apiserver authentication through the app values: no knob for OIDC, the structured AuthenticationConfiguration, extra apiserver flags, or extra volumes. The only workaround was patching the underlying KamajiControlPlane out-of-band, which is invisible to GitOps and lost on recreation. Add three opt-in fields under controlPlane.apiServer, all empty by default so existing clusters render unchanged: - extraArgs -> KamajiControlPlane spec.apiServer.extraArgs - extraVolumeMounts -> spec.apiServer.extraVolumeMounts - extraVolumes -> appended to spec.deployment.extraVolumes This unblocks OIDC SSO via the --oidc-* flags and, more importantly, structured authentication: --authentication-config mounted from a ConfigMap/Secret plus --requestheader-uid-headers, which is the only way to map a user UID for aggregated/extension apiservers. Because the control-plane Deployment runs on the management cluster, the passthrough is validated to preserve tenant<->management isolation: - extraVolumes allow only configMap and secret sources; host-reaching sources (hostPath, csi, nfs, persistentVolumeClaim) and token projection (projected) are rejected, so a tenant with self-service access to the Kubernetes CR cannot mount management-node paths or project arbitrary tokens into the apiserver pod. - each extraVolume must have a unique, non-empty name and exactly one source; the reserved names talos-ca and talos-tls-cert are rejected to avoid a duplicate volume name in the rendered podspec. - each extraVolumeMount must reference a user-declared extraVolume; the chart-managed talos secret volumes cannot be mounted. Regenerate values.schema.json, README, the Go types and deepcopy, and the ApplicationDefinition. Add helm unittest coverage for the default (no-op) render, each field's passthrough, the name/source guards, and the mount-reference guard (valid and rejected inputs). Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la> |
||
|
|
021f6141ca |
feat(kubernetes): propagate remote-accessible LINSTOR StorageClasses to tenant clusters
Tenant Kubernetes clusters previously exposed a single hardcoded "kubevirt" StorageClass mapped to one infra class. Discover all remote-accessible LINSTOR infra StorageClasses (provisioner linstor.csi.linbit.com, allowRemoteVolumeAccess != false) via Helm lookup and propagate each to the tenant under the same name. - csi.yaml builds a storageClasses map filtered to remote LINSTOR classes; node-local classes (e.g. "local") are excluded because the backing volume cannot follow a live-migrated worker VM. - The class named by .Values.storageClass (default "replicated") is marked the tenant default; the legacy "kubevirt" StorageClass is kept as a non-default alias so existing tenant PVCs keep binding. - A non-destructive fallback preserves the legacy mapping when the lookup returns empty (dry-run), so tenant StorageClasses are never wiped on a transient reconcile. - infraStorageClassEnforcement is intentionally left disabled (AllowAll) to avoid breaking tenants that already self-served custom StorageClasses under the current default. Refs: #2094, #1424 Assisted-By: Claude <noreply@anthropic.com> Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com> |
||
|
|
13f1f9ece1 |
feat(api): add network.cozystack.io ExposureClass and ServiceExposure
Introduce a new network.cozystack.io/v1alpha1 API group with two kinds that form the mechanism-agnostic LoadBalancer exposure model: - ExposureClass (cluster-scoped): the admin binds a logical class to a concrete backend (externalIPs, metallb, cilium, robotlb) and its VIP address scope, following the StorageClass / IngressClass pattern. - ServiceExposure (namespaced): the tenant-facing intent to expose a Service externally via a named class, with status reporting the resolved backend and assigned IPs. Wire api/network into the controller-gen CRD generation so deepcopy and the two CRD manifests are produced alongside the existing groups. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la> |
||
|
|
2b25163a8f |
refactor(sdn)!: reshape SecurityGroup into a membership-group model
Give each SecurityGroup its own membership label (securitygroup.sdn.cozystack.io/<name>) and select it from the backing CiliumNetworkPolicy, instead of deriving the endpointSelector from a single app's lineage labels. spec.targetRef becomes spec.attachments, so one SecurityGroup can apply to several applications at once. Peers move from free-form fromEndpoints/toEndpoints selectors to fromApp/toApp (resolved to lineage labels) and fromSG/toSG (resolved to another group's membership label, a reference the Cilium dataplane resolves live). Attachments are persisted in a storage-owned CiliumNetworkPolicy annotation, round-tripped and hidden from the SecurityGroup view like the marker label. Validation now covers attachments and app/SG peers and rejects names that collide with reserved Cilium entities. The membership labels are maintained by a separate controller added in a follow-up commit; this change covers the API types and the aggregated-apiserver projection only. BREAKING CHANGE: SecurityGroup spec.targetRef is replaced by spec.attachments, and ingress/egress peers use fromApp/fromSG/toApp/toSG instead of fromEndpoints/toEndpoints. The feature is unreleased, so no migration is required. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la> |
||
|
|
39cdc88661 |
feat(kubernetes): bootstrap tenant workers with Talos via CABPT
Switch tenant worker bootstrap from Ubuntu+kubeadm to Talos. MachineDeployment.bootstrap moves from KubeadmConfigTemplate to a TalosConfigTemplate produced by a post-install/upgrade reconcile hook, which also materialises the kubeadm-format bootstrap-token Secret in the tenant kube-system. Workers boot from the Talos openstack image via a CDI DataVolume; the system disk is virtio-blk with logical=512/physical=4096 so 4Ki-native backends (LINSTOR/DRBD) and SeaBIOS both work; the separate kubelet disk is dropped. Pod/service CIDRs, dnsDomain, controlPlane endpoint and cilium k8sServiceHost are pinned to the tenant ranges / Kamaji apiserver ClusterIP to survive the DNS chicken-and-egg at bootstrap. Adds a Talos<->Kubernetes support-matrix fail() guard and drops v1.30. Removes the dead ubuntu-container-disk build chain and the orphaned copy-patch-containerd template. Co-authored-by: IvanHunters <xorokhotnikov@gmail.com> Co-authored-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com> Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Andrei Kvapil <kvapss@gmail.com> Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com> |
||
|
|
4679cfdd95 |
feat(sdn): add SecurityGroup API types
Introduce the sdn.cozystack.io/v1alpha1 API group with the SecurityGroup resource. SecurityGroup is a namespace-scoped, tenant-facing firewall object whose spec mirrors the subset of the CiliumNetworkPolicy rule that the abstraction exposes (endpointSelector, ingress, egress, ports, CIDR, FQDN), so the resource can be projected 1:1 onto a CiliumNetworkPolicy without granting tenants direct access to the cilium.io API group. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la> Co-authored-by: Timofei Larkin <lllamnyp@gmail.com> |
||
|
|
e8e750ccb0 |
feat(platform): operator-provided wildcard certificate for platform and tenant ingress (#2819)
## What this PR does Adds an operator-facing way to serve platform services and the root tenant's ingress under a pre-existing wildcard TLS certificate instead of minting per-host ACME certificates. Implements the "native references" design decided on #2812. A single value, `publishing.certificates.wildcardSecretName`, names a TLS Secret the operator has already created in the publishing namespace (`tenant-root` by default). Only the name travels through the `cozystack-values` channel — the certificate and private key are never broadcast, unlike the public `kube-root-ca` that already rides it. When set: - **ingress-nginx path** (`gateway.enabled=false`): the publishing tenant's ingress controller serves the Secret as its `--default-ssl-certificate`, and the platform service Ingresses drop their cert-manager cluster-issuer annotation and `tls` block. No per-host ACME. - **Gateway API path** (`gateway.enabled=true`): a new `TenantGateway` cert mode, `existingSecret`, references the Secret in the wildcard/apex listener `certificateRefs` and mints no Issuer or Certificate. Switching into this mode garbage-collects any ACME machinery left from `http01`/`dns01`. Scope is the root tenant — everything is same-namespace, so no RBAC or NetworkPolicy changes. Extending wildcard mode to child tenants needs the Secret replicated into each tenant namespace and is left as a follow-up. Closes #2812. Part of #2811. ### Screenshots N/A — no UI changes. ### Release note ```release-note feat(platform): operators can serve platform services and the root tenant's ingress under a pre-existing wildcard TLS certificate via `publishing.certificates.wildcardSecretName`, instead of minting per-host ACME certificates ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added an "existingSecret" TLS certificate mode and a wildcardSecretRef option for TenantGateway and platform values to use a pre-existing wildcard TLS Secret. * **Platform / Templates** * Introduced operator "wildcard secret" mode across Gateway and many Helm charts (Ingress, apps) to skip per-host ACME provisioning and optionally wire a default SSL cert. * **Tests** * Added extensive chart and controller tests covering existingSecret behavior and cert-mode transitions. * **Documentation** * Updated gateway docs describing the new wildcard secret mode and requirements. * **Chores** * Added Helm unit test makefile targets to several packages. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
d739663298 |
fix(deps): bump golang.org/x/net to v0.55.0 in api/apps/v1alpha1 submodule
The submodule still pulled golang.org/x/net v0.53.0, affected by GO-2026-5026 (failure to reject ASCII-only Punycode-encoded labels in golang.org/x/net/idna, which the submodule imports). The root module was already on v0.55.0; align the submodule so the advisory is closed across both go.mod files. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la> |
||
|
|
8497fc6f6f |
fix(deps): bump Go to 1.26.4 and x/net to v0.55.0 to close OSV advisories
Clears the OpenSSF Scorecard Vulnerabilities check (was 0/10). An osv-scanner pass over both go.mod files reported 12 advisories: - 10 stdlib advisories against the Go toolchain pinned at 1.26.2 (GO-2026-4918/4971/4977/4980/4982/4986 fixed in 1.26.3; GO-2026-5037/5038/5039 fixed in 1.26.4) — closed by raising the go directive to 1.26.4 in both the root module and api/apps/v1alpha1. - golang.org/x/net 0.52.0 (GO-2026-4918, GO-2026-5026) — bumped to v0.55.0; go mod tidy carried the matching x/crypto, x/sys, x/term, x/text and x/tools minor bumps via MVS. After the bump osv-scanner reports 0 advisories. Both modules build, and 'make generate' produces no drift (codegen-drift stays green). Versions were changed with 'go mod edit'/'go get'/'go mod tidy', not by hand-editing the generated go.mod. Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com> Assisted-By: Claude <noreply@anthropic.com> |
||
|
|
4262658f0f |
feat(tenantgateway): add existingSecret cert mode for operator wildcard
Operators who already hold a wildcard TLS certificate (purchased, or issued by a corporate CA) had no way to make a tenant Gateway serve under it: the only cert modes were http01 (per-listener ACME) and dns01 (controller-minted wildcard via ACME). Add a third mode, existingSecret, that references a pre-existing TLS Secret in the TenantGateway's own namespace via spec.wildcardSecretRef. In this mode the controller mints no ACME Issuer and no Certificate; the wildcard, apex, and per-child-apex HTTPS listeners reference the supplied Secret directly. A missing wildcardSecretRef fails fast with Ready=False rather than producing a Gateway pointing at a nonexistent Secret. Switching into existingSecret from http01/dns01 reclaims the now-unused Issuer and Certificates so no ACME machinery is left behind. The non-cert listeners (http->https redirect, TLS passthrough) are unaffected and continue to render. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la> |
||
|
|
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>
|
||
|
|
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> |
||
|
|
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 --> |
||
|
|
5c4e9277fc |
fix(foundationdb): regenerate types.go and README for split imageType default
The imageType default was switched to split in values.yaml/values.schema.json/ RD schema but make generate was not run, leaving the +kubebuilder:default marker in api/apps/v1alpha1/foundationdb/types.go at "unified" and the README param table sized for the old value — failing the pre-commit generate check (exit 123). Regenerated with cozyvalues-gen v1.5.0. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com> |
||
|
|
94f463d61a |
feat(postgres): add TLS support via CNPG operator-managed certificates (#2686)
## What this PR does Adds TLS support to the Postgres managed service via the CNPG operator's built-in cert management. - Introduces a nullable `tls.enabled` field with tri-state semantics: when unset, defaults to the value of `external` (auto-on for externally published services, off for cluster-internal). Explicit `tls.enabled` always wins. - Uses CNPG's operator-managed TLS chain — the chart no longer renders its own cert-manager chain. The operator auto-generates a self-signed CA and signs server, client, and replication certs from it. The operator's default SAN list already covers the three built-in services (rw/r/ro) in four DNS forms each (bare, `.ns`, `.ns.svc`, `.ns.svc.<cluster-domain>`). - When `external: true` and TLS is on, the chart sets `spec.certificates.serverAltDNSNames` so the operator appends the external hostname `<release>.<tenant-host>` to the auto-generated leaf cert. In all other cases the chart leaves `spec.certificates` absent and the operator uses its default SAN set. - Trust anchor for clients: the operator-managed `<release>-ca` Opaque Secret (key `ca.crt`). Mount that key into client pods to verify TLS. Why operator-managed instead of a chart-side cert-manager chain: an earlier iteration that supplied `serverCASecret` and `serverTLSSecret` from a chart-rendered cert-manager chain failed the CNPG admission webhook with `missing ca.key secret data`. CNPG expects a `ca.key` field on `serverCASecret`, while cert-manager writes the private key under `tls.key`. Operator-managed mode avoids the schema fight entirely. Verified end-to-end on a sandbox cluster: cert chain is created by the operator within ~60 seconds, leaf cert's SAN list includes both the standard service forms and the external hostname, TLSv1.3 handshake via `openssl s_client -starttls postgres` against the rw service with the operator CA returns verify code 0. ### Release note ```release-note feat(postgres): add TLS support via CNPG operator-managed certificates with tri-state tls.enabled ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * TLS configuration added for PostgreSQL with a tri-state tls.enabled to control operator-managed certificate behavior and optional injection of the external hostname into server certificate SANs. * **Documentation** * Added TLS configuration guide, client CA retrieval and psql verification examples, and updated parameters reference. * **Tests** * Added integration tests covering tri-state TLS behavior and external-hostname injection scenarios. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/cozystack/cozystack/pull/2686?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 --> |
||
|
|
41bab0c462 |
feat(qdrant): add TLS support via cert-manager (#2685)
## What this PR does Adds TLS support to the Qdrant managed service via cert-manager. - Introduces a nullable `tls.enabled` field with tri-state semantics: when unset, defaults to the value of `external` (auto-on for externally published services, off for cluster-internal). Explicit `tls.enabled` always wins. - Renders a self-contained cert-manager chain in the tenant namespace: self-signed Issuer, CA Certificate, CA Issuer, leaf Certificate. - SAN policy covers the three DNS forms per service (bare, `.ns.svc`, `.ns.svc.<cluster-domain>`) plus the external hostname when `external: true`. - Wires the leaf cert into the Qdrant HelmRelease so both the REST and gRPC endpoints use the chart-managed CA chain. Verified end-to-end on a sandbox cluster: cert chain reaches Ready, TLS handshake against the tenant service succeeds with the chart CA bundle. ### Release note ```release-note feat(qdrant): add TLS support via cert-manager (tri-state tls.enabled) ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * TLS config for Qdrant with tri-state behavior (inherit from external, or explicitly enable/disable); optional cert-manager provisioning and automatic TLS secret mounting. * **Documentation** * README and chart values/schema updated to document TLS parameters, defaults, and precedence. * **Tests** * Expanded Helm tests covering TLS rendering, certificates (SANs/ECDSA), reload annotations, and volume/secret injection. * **Chores** * Added a Helm test target to the Makefile. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/cozystack/cozystack/pull/2685?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 --> |
||
|
|
e76bde7676 |
feat(nats): add TLS support via cert-manager (#2684)
## What this PR does Adds TLS support to the NATS managed service via cert-manager. - Introduces a nullable `tls.enabled` field with tri-state semantics: when unset, defaults to the value of `external` (auto-on for externally published services, off for cluster-internal). Explicit `tls.enabled` always wins. - Renders a self-contained cert-manager chain in the tenant namespace: self-signed Issuer, CA Certificate, CA Issuer, leaf Certificate. - SAN policy covers the three DNS forms per service (bare, `.ns.svc`, `.ns.svc.<cluster-domain>`) plus the external hostname when `external: true`. - Wires the leaf cert into the NATS HelmRelease so client connections and cluster routes both use the chart-managed CA chain. Verified end-to-end on a sandbox cluster: cert chain reaches Ready, TLS handshake against the tenant service succeeds with the chart CA bundle. ### Release note ```release-note feat(nats): add TLS support via cert-manager (tri-state tls.enabled) ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added optional TLS support for NATS with a nullable/tri-state tls.enabled (true/false/null) that defaults to external access when unset * Conditional cert-manager integration to provision CA and TLS certificates and enable cluster TLS, and toggle cluster routing to FQDN when TLS is enabled * **Documentation** * Updated configuration docs and schema defaults to include new TLS settings and fallback behavior * **Tests** * Added tests validating tri-state TLS behavior, cert-chain generation, SANs, and conditional rendering <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/cozystack/cozystack/pull/2684?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 --> |
||
|
|
17b2fb70a3 |
feat(kafka): add TLS support via Strimzi listener configuration (#2681)
## What this PR does Adds TLS support to the Kafka managed service via Strimzi listener configuration. - Introduces a `tls.enabled` field that controls the external listener (port 9094). When unset, defaults to the value of `external` (auto-on when external access is enabled). Explicit `tls.enabled` always wins. - Strimzi manages the cluster PKI automatically; the operator publishes `<release>-cluster-ca-cert` and `<release>-clients-ca-cert` for client trust setup. No cert-manager chain is rendered by this chart — the operator owns the chain end-to-end. - The internal TLS listener on 9093 is always on (Strimzi default); this field only governs the external listener on 9094. - External LoadBalancer listener is decoupled from `tls.enabled`: it is gated on `external: true` only. Previously, an explicit `tls.enabled: true` with `external: false` would force the external listener to be rendered. Verified end-to-end on a sandbox cluster: external listener exposes a TLS endpoint signed by the Strimzi-managed cluster CA, client connections with the published trust bundle succeed. Note: this chart does not configure listener authentication. With TLS on the external listener, clients can connect without credentials unless `KafkaUser` resources with `tls`/`scram-sha-512`/`oauth` authentication are configured outside this chart. ### Release note ```release-note feat(kafka): add TLS support on the external listener via Strimzi (tri-state tls.enabled) ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Tri-state TLS for the external Kafka listener: explicit on, explicit off, or inherit from the external toggle; chart values now include a top-level tls object. * **Documentation** * Expanded chart docs/README clarifying tls.enabled inheritance, plaintext risk when disabled with external access, and authentication guidance. * **Tests** * Added/updated schema, rendering, RBAC/secret-naming, helm unit, and end-to-end tests covering TLS tri-state and external-listener behavior. * **Bug Fixes** * RBAC and secret-name expectations updated to use the `-cert` suffixed secret names. * **Chores** * Added a Makefile test target to run helm unit tests. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/cozystack/cozystack/pull/2681?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 --> |
||
|
|
d052227dc4 |
Merge branch 'main' into feat/tls-postgres
Resolve the conflict in the generated packages/system/postgres-rd/cozyrds/postgres.yaml by regenerating openAPISchema and keysOrder from the merged values. The CRD now carries both the chart's tls.enabled field and main's backup useSystemBucket / BackupClass-driven fields. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Arsolitt <arsolitt@gmail.com> |
||
|
|
f17ead3d26 |
feat(platform): add default backupclass
Signed-off-by: Andrey Kolkov <androndo@gmail.com> |
||
|
|
d7934b89d0 |
refactor(postgres): move version param out of the TLS section
version is a general deployment parameter, not a TLS setting; relocate its @param/@enum block back into Common parameters so the generated parameter reference groups it correctly instead of under TLS. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Arsolitt <arsolitt@gmail.com> |
||
|
|
18de2119d9 |
docs(postgres): describe tls.enabled default as omitted, not null
The generated JSON schema types tls.enabled as a scalar boolean, which rejects an explicit null value; describe the tri-state unset case as "omitted" so the wording matches what the schema actually accepts. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Arsolitt <arsolitt@gmail.com> |
||
|
|
72c4eb9c08 |
feat(backups): implement Job backup strategy (#1721)
## What Implements the `strategy.backups.cozystack.io/Job` backup strategy — a generic, application-agnostic driver that runs a user-supplied Kubernetes Job to create (and restore) a backup. ## Background This PR began as a draft written against an earlier shape of the backups API. The API has since moved to a `BackupClass`-based dispatch model, which broke the original draft on three counts: - `BackupJob.Spec.StrategyRef` and `BackupJob.Spec.StorageRef` were removed; the strategy and its parameters are now resolved from a `BackupClass` into a `ResolvedBackupConfig`. - Strategy handling moved from standalone per-strategy reconcilers to a dispatch model: `BackupJobReconciler.Reconcile` / `RestoreJobReconciler.Reconcile` resolve the strategy and switch into per-strategy methods (`reconcileVelero`, `reconcileCNPG`, `reconcileAltinity`, …). - The draft's template context (`.Values`, `.Storage`) diverged from the convention the other strategies adopted, and its `.Storage` half targeted a storage API that does not exist. ## What changed - **`reconcileJob` / `reconcileJobRestore`** (`internal/backupcontroller/jobstrategy_controller.go`): replaces the standalone `BackupJobStrategyReconciler` with the two dispatch methods the `BackupJob` / `RestoreJob` reconcilers call. The Job strategy is the generic counterpart of the Altinity driver — same lifecycle (render `PodTemplateSpec` → run a one-shot `batch/v1.Job` → poll its terminal condition → emit a `Backup`), minus the ClickHouse-specific `applicationRef` gate, so it runs for any application. Shared package helpers (`renderJobTemplate`, `jobConditionState`, `getApplicationUnstructured`, status helpers, deterministic Job naming, controller refs) are reused. - **Template context** follows the in-tree convention used by the other drivers: `.Application` (live application object), `.Release.Name` / `.Release.Namespace`, `.Mode` (`backup` / `restore`), `.Parameters` (resolved `BackupClass` parameters), and `.Backup` (restore runs only). Strategy parameters round-trip through the `Backup`'s `driverMetadata` so a later restore re-renders against the same values. - **Restore** re-renders the same template with `.Mode == "restore"`. Cross-namespace restore is unsupported (the RestoreJob target reference is namespace-local), matching the Altinity driver. - **`JobSpec.Template` doc + regenerated CRD**: the field doc previously advertised `.Values`; it now documents the real context, and `strategy.backups.cozystack.io_jobs.yaml` is regenerated to match (the change is limited to that field's description). - **Tests** (`jobstrategy_controller_test.go`): backup-Job creation / args / labels / status, completion → `Backup` artifact with parameter round-trip, Job-failure surfacing, missing-strategy terminal failure, restore into the target namespace, restore completion, and the parameter-prefix unit. A deliberately generic application kind pins that the driver never gates on `applicationRef.kind`. No RBAC changes are required: the controller already holds `strategy.backups.cozystack.io/*`, `batch/jobs`, `apps.cozystack.io/*`, and `backups` permissions. ## Notes for reviewers - Backup and restore share one template, so a strategy author's `PodTemplateSpec` must branch on `.Mode` to do anything restore-specific. This matches the existing convention; worth confirming it's the intended contract for the Job strategy's docs/examples. 🤖 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** * Implemented full backup/restore job strategy with deterministic Job creation, idempotent execution, and status/condition updates; added demo example scripts and reusable shell helpers for a NATS JetStream backup/restore workflow. * **Documentation** * Clarified Job template rendering context and listed supported template variables; added README and step-by-step scenario docs for the NATS example. * **Tests** * Added comprehensive unit tests covering job creation, completion/failure handling, parameter extraction, and unmappable-target failure cases. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/cozystack/cozystack/pull/1721?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 --> |
||
|
|
bc6c3f2611 |
docs(postgres): rewrite TLS section for operator-managed CNPG flow
The README still described the chart-side cert-manager chain that was replaced when the chart switched to CNPG operator-managed TLS via spec.certificates.serverAltDNSNames. Rewrite the section to explain the actual cert ownership boundary (CNPG owns the chain, chart only injects the external hostname), the trust anchor location (operator-managed <release>-ca Secret, key ca.crt), and the chart-side semantics of the tri-state tls.enabled flag. The values.yaml @field comment is updated in the same direction, with regenerated schema/types.go/cozyrds. Clarifies that tls.enabled=false only skips the chart-side SAN injection - CNPG retains its built-in TLS on the wire regardless of this flag. To force PostgreSQL TLS off entirely, the caller would set postgresql.parameters.ssl="off" at the CNPG layer. Signed-off-by: Arsolitt <arsolitt@gmail.com> |
||
|
|
df4f6522c5 |
chore(postgres): tidy go.mod to demote unused direct dependency to indirect
Signed-off-by: Arsolitt <arsolitt@gmail.com> |
||
|
|
114a69d3ce |
feat(postgres): add TLS schema and generated artifacts
- Extend PostgresSpec with nullable Tls.Enabled (*bool) for tri-state control - Regenerate deepcopy and update go.mod with k8s.io/utils as direct dep - Add TLS fields to values.yaml, values.schema.json (with nullable support) - Update README and Makefile; propagate TLS field to cozyrds postgres.yaml Signed-off-by: Arsolitt <arsolitt@gmail.com> |
||
|
|
17089eec0a |
chore(qdrant): regenerate codegen deepcopy artifacts
Signed-off-by: Arsolitt <arsolitt@gmail.com> |
||
|
|
612274693f |
feat(qdrant): add TLS schema and configuration artifacts
- Extend QdrantSpec with tls.enabled tri-state bool and expose it via values.yaml and JSON schema - Update cozyrds integration to pass TLS config to the operator - Add test: Makefile target and TLS parameter documentation to README Signed-off-by: Arsolitt <arsolitt@gmail.com> |
||
|
|
85f9cc9727 |
chore(nats): regenerate codegen artifacts
Signed-off-by: Arsolitt <arsolitt@gmail.com> |
||
|
|
81239b332d |
feat(nats): add TLS schema and generated artifacts
- Extend values.yaml and JSON schema with tls.enabled (*bool tri-state) and tls.secretName fields - Update Go types and regenerate README for TLS field - Enable TLS toggle in nats-rd cozyrds config - Wire helm-unittest into Makefile as test target Signed-off-by: Arsolitt <arsolitt@gmail.com> |
||
|
|
80a01fd330 |
chore(kafka): regenerate codegen deepcopy artifacts
Signed-off-by: Arsolitt <arsolitt@gmail.com> |
||
|
|
2eba34618c |
feat(kafka): add TLS schema and generated artifacts
- Add tri-state tls.enabled (*bool) to Kafka API types for strict nil/true/false semantics - Extend values.yaml and JSON schema with TLS configuration block - Update Makefile with sed+jq patching for nullable bool schema and test target - Update cozyrds schema to reflect nullable tls.enabled type - Update README with Strimzi-managed PKI documentation and authentication notes Signed-off-by: Arsolitt <arsolitt@gmail.com> |
||
|
|
b630706df6 |
feat(apps): mark stateful-app storageClass fields as immutable (#2639)
## Summary Annotate `storageClass` as immutable across every stateful chart that exposes one: clickhouse, foundationdb, harbor, http-cache, kafka (Kafka + ZooKeeper), kubernetes (top-level + nodeGroups[]), mariadb, mongodb, nats, openbao, opensearch, postgres, qdrant, rabbitmq, redis, vm-disk. The PVC-pinning argument is identical for every chart — Kubernetes fixes `storageClassName` on each PVC at creation, so editing this field on an existing resource never migrated data; the schema annotation makes that contract explicit and lets schema-aware consumers refuse the edit up-front. Schema-aware consumers today: the Cozystack UI (cozystack/cozystack-ui#6) reads the rule from the chart's openAPISchema and renders the field read-only on edit forms. This PR is **schema-side only**. The cozystack aggregated apiserver does not yet evaluate CEL rules in `openAPISchema` (`MariaDB` / `Postgres` / etc. are application-backed, not CRDs); tracking issue cozystack/cozystack#2657 covers wiring CEL into `pkg/registry/apps/application/rest.go::Update`. Until that lands, an apiserver-level `kubectl patch` that changes `storageClass` is still accepted — but the underlying StatefulSet PVCs do not move, so there's no data-corruption risk, only a confusing UX. The UI catches that case today; the apiserver gate closes it permanently. ## What changes For each app in the list above: - `packages/apps/<app>/values.yaml` — gain a `## @immutable` directive directly above (or below, for fields inside a `@typedef`) the `storageClass` line. - Regenerated via `make generate` in each package: - `api/apps/v1alpha1/<app>/types.go` — kubebuilder `XValidation` marker on the relevant field(s). - `packages/apps/<app>/values.schema.json` — `x-kubernetes-validations: [{rule: "self == oldSelf", message: …}]` on `storageClass`. - `packages/apps/<app>/README.md` — regenerated parameter table. - `packages/system/<app>-rd/cozyrds/<app>.yaml` — the embedded `openAPISchema` on the ApplicationDefinition reflects the change. Refactor: `pkg/registry/apps/application/rest.go` factors the inline schema-build path into a new `buildSpecSchema` helper so it can be unit-tested without standing up a fake apiserver. Three regression tests in `pkg/registry/apps/application/rest_spec_schema_test.go` pin the contract that `x-kubernetes-validations` survives the v1→internal→structural conversion (test loads the actual MariaDB ApplicationDefinition fixture on disk, asserts the rule reaches the structural schema). Empty-input and malformed-JSON paths are also pinned. No e2e admission test is added because the apiserver does not yet enforce the rule — see cozystack/cozystack#2657. No changelog entry: schema-side annotation is invisible at the apiserver layer today (UI-only consumer) and the release-cut PR will add the entry when admission enforcement lands. ## Dependencies Requires cozystack/cozyvalues-gen#24 to be merged and released, and the `cozyvalues-gen` binary pin in `.github/workflows/pre-commit.yml` line 50 bumped to the release that includes that PR. Pre-commit CI will fail until both happen — the stock `v1.3.0` binary silently ignores `## @immutable` and regenerates artefacts without the rule, producing a drift against what's committed. Once that ordering is satisfied, rebase this branch and the pre-commit job will be green. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * storageClass is now treated as immutable after creation for many stateful apps (enforced by chart/CRD schema validation). * **Documentation** * Added a storage immutability guide explaining the contract and enforcement. * Updated chart READMEs and values docs to mark storageClass as immutable and clarified nodeGroup storage remains intentionally mutable. * **Tests** * Added tests validating schema parsing and preservation of immutability rules. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/cozystack/cozystack/pull/2639?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 --> |
||
|
|
5af5962edf |
feat(apps): mark stateful-app storageClass fields as immutable
Annotate storageClass as immutable across every stateful app whose chart exposes one — clickhouse, foundationdb, harbor, http-cache, kafka (Kafka + ZooKeeper), kubernetes (top-level only), mariadb, mongodb, nats, openbao, opensearch, postgres, qdrant, rabbitmq, redis, vm-disk. Without coverage across the catalogue the UI would render storageClass read-only on some apps and editable on others — a worse mental model than uniform behaviour. The annotation lands at the schema layer (CEL XValidation rule 'self == oldSelf' on values.schema.json / types.go / embedded openAPISchema in cozyrds/<app>.yaml). The cozystack aggregated apiserver does not yet evaluate CEL on application-backed resources; that is tracked at cozystack/cozystack#2657. The UI (cozystack/cozystack-ui#6) consumes the marker today. The PVC-pinning argument is identical for every chart: Kubernetes fixes a PVC's storageClassName at creation time, so editing this field on an existing resource never migrated data. The schema annotation makes that contract explicit. kubernetes.nodeGroups[name].storageClass is intentionally NOT annotated: the field is optional and undefaulted, so a strict 'self == oldSelf' rule would block any future attempt to set it on an existing node group. A richer ratcheting form is needed there — see docs/storage-immutability.md. A refactor in pkg/registry/apps/application/rest.go extracts the inline schema-build path into buildSpecSchema so it can be unit-tested. Three regression tests in rest_spec_schema_test.go pin the contract that x-kubernetes-validations survives the v1->internal->structural conversion (loaded from the actual MariaDB ApplicationDefinition fixture on disk, not a hand-edited mock). Each per-app README gains a one-line blockquote pointing to a new docs/storage-immutability.md that explains the contract and which consumers enforce it today. Requires cozystack/cozyvalues-gen with @immutable support — bump the pre-commit pin in .github/workflows/pre-commit.yml once the release exists. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la> |
||
|
|
d2e851f63b |
feat: Gateway API support via Cilium
Replace ingress-nginx as the default ingress layer for cozystack-native
services with Cilium Gateway API, materialised per-tenant via a new
TenantGateway CRD reconciled by cozystack-controller.
The extra/gateway chart renders one gateway.cozystack.io/v1alpha1
TenantGateway per tenant; the controller owns the resulting Gateway,
per-tenant Issuer, Certificate(s), and the http->https redirect
HTTPRoute. This avoids the helm-vs-controller race on
Gateway.spec.listeners when route-driven listeners are added.
publishing.certificates.solver selects HTTP-01 (default; per-app HTTPS
listener + per-app Certificate) or DNS-01 (opt-in; single wildcard
Certificate per apex; providers: cloudflare, route53, digitalocean,
rfc2136). HTTP-01 keeps zero-config per-app onboarding; DNS-01 saves
Let's Encrypt budget on apex-shared clusters.
Security model -- seven independent layers, all admission-time gates
fail-closed:
1. Listener allowedRoutes namespace whitelist via the
kube-apiserver-written kubernetes.io/metadata.name label;
plain-HTTP listener is strictly narrower than HTTPS, and HTTPS /
passthrough listeners restrict allowedRoutes.kinds to
HTTPRoute / TLSRoute respectively.
2. cozystack-gateway-hostname-policy VAP on Gateway.
3. cozystack-gateway-attached-namespaces-policy VAP on Package --
blocks tenant-* in gateway.attachedNamespaces.
4. cozystack-tenant-host-policy VAP on Tenant -- blocks spec.host
writes from non-trusted callers.
5. cozystack-namespace-host-label-policy VAP on Namespace -- blocks
writes to namespace.cozystack.io/host from non-trusted callers.
6. Render-time fail in cozystack-basics for tenant-* in
gateway.attachedNamespaces.
7. cozystack-route-hostname-policy VAP on HTTPRoute / TLSRoute,
scoped to tenant-* namespaces.
Within-apex cross-namespace hostname conflict is resolved at reconcile
time by a HostnameConflict condition (cozy-* namespace wins).
Five reconcile paths refuse to rewrite pre-existing objects with the
controller-derived name but no OwnerReference back to the
TenantGateway: Gateway, redirect HTTPRoute, per-tenant Issuer, wildcard
Certificate, per-listener Certificate.
Derived-apex tenants (tenants whose host is a subdomain of a parent
tenant's) auto-enable Gateway when the platform-level gateway.enabled
is on.
Bonus fix: pkg/registry/apps/application/rest.go was ignoring the
createValidation and deleteValidation callbacks that genericapiserver
hands to every storage method, silently bypassing admission for Create
and Delete on every apps.cozystack.io resource (Tenant, MariaDB,
Postgres, Kubernetes, ...). Aligned with the existing updateValidation
pattern.
Always-on changes: cilium.envoy.enabled + cilium.gatewayAPI.enabled
flip to true (extra cilium-envoy DaemonSet, ~100 MB RAM/node idle),
and the cozystack-api admission-chain fix. Everything else is gated
behind gateway.enabled=false and tenant.spec.gateway=false; existing
clusters see no behavioural change until an operator opts in.
Tests: 60+ Go cases in internal/controller/tenantgateway/, admission-
chain regression tests in pkg/registry/apps/application/, helm-unittest
across 7 charts (extra/gateway, core/platform, apps/tenant,
system/cozystack-basics, system/cert-manager-issuers,
system/cozystack-api, system/dashboard), and 14 e2e bats scenarios in
hack/e2e-apps/gateway.bats. New make test-controllers target wired
into pull-requests.yaml.
Deps: sigs.k8s.io/gateway-api v1.4.1, cert-manager v1.17.4.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
|
||
|
|
02911493f4 |
feat(backups): implement Job backup strategy
Complete the strategy.backups.cozystack.io/Job driver as the generic, app-agnostic counterpart to the Altinity driver: render the strategy PodTemplateSpec, run it as a one-shot batch/v1.Job, poll its terminal condition, and emit a Backup. Wire it into the existing BackupClass dispatch via reconcileJob/reconcileJobRestore rather than a standalone reconciler, matching the post-BackupClass backups API (the old draft read BackupJob.Spec.StrategyRef/StorageRef, which no longer exist). Template context follows the in-tree convention (.Application, .Release, .Mode, .Parameters, .Backup); the JobSpec.Template doc and regenerated CRD are updated to match. Restore re-renders the same template with .Mode=restore; cross-namespace restore is unsupported, mirroring Altinity. Signed-off-by: Timofei Larkin <lllamnyp@gmail.com> |
||
|
|
debb9f85db |
feat(platform): add implementation of backup-strategy controller for etcd (#2641)
<!-- 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 ### 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. --> ### 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 add implementation of backup-strategy controller for etcd ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Cluster-scoped Etcd backup strategy CRD (S3-only) plus controller support for BackupJob (snapshot → Backup) and destructive in-place RestoreJob flows; snapshot metadata persisted and destination validation enforced. * **Documentation** * Complete etcd backup/restore README and admin/tenant scenario guides. * **Examples & Tests** * End-to-end demo scripts (helpers, stepper, cleanup, runner), Bats e2e, and extensive unit tests. * **Chores** * RBAC updates for etcd access, chart version bumped, demo env files added to .gitignore. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/cozystack/cozystack/pull/2641?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 --> |
||
|
|
d80f67e799 |
feat(platform): add implementation of backup-strategy controller for etcd
Signed-off-by: Andrey Kolkov <androndo@gmail.com> |