## Why Follow-up to #2509. PR #2509 exposed five HelmRelease generation knobs as `cozystack-operator` flags (`--helmrelease-{interval,retry-interval,install-timeout,upgrade-timeout,max-history}`). The other HelmRelease-generating path — `cozystack-api`'s `convertApplicationToHelmRelease` in `pkg/registry/apps/application/rest.go` — was deliberately left out of #2509's scope and was flagged in review: > `pkg/registry/apps/application/rest.go` (the other HelmRelease-generating path) still hardcodes `Interval: 5m`, `Remediation{Retries:-1}`, no `Strategy`. Out of this PR's scope; worth a Followups bullet so the rationale doesn't drift across paths. So today the api-side path hardcodes: - `Spec.Interval = 5m` - `Install.Remediation{Retries: -1}` + `Upgrade.Remediation{Retries: -1}` - no `Strategy` - no `MaxHistory` Only `HelmInstallTimeout` (per-Application annotation override) flows through `ReleaseConfig`. This PR brings the api-side to feature parity with the operator: same flag names, same defaults, same validation, same generated HelmRelease shape. ## What ### New cozystack-api flags Names, types, defaults, and validation match the operator's flags introduced in #2509 verbatim, so both binaries can be tuned with the same vocabulary. | Flag | Default | HR field | |---|---|---| | `--helmrelease-interval` | `5m` | `Spec.Interval` | | `--helmrelease-retry-interval` | `30s` | `Spec.{Install,Upgrade}.Strategy.RetryInterval` | | `--helmrelease-install-timeout` | `10m` | `Spec.Install.Timeout` | | `--helmrelease-upgrade-timeout` | `10m` | `Spec.Upgrade.Timeout` | | `--helmrelease-max-history` | `5` | `Spec.MaxHistory` | Validated in `CozyServerOptions.Complete()` via `config.ParsePositiveDuration` so a misconfigured server restarts loudly instead of waiting until the first Application is created. `MaxHistory < 0` is rejected; `0` is honored (unlimited per Helm semantics, matching the operator). ### Strategy switch `Install.Strategy.Name` and `Upgrade.Strategy.Name` are now set to `RetryOnFailure` (with `RetryInterval` from the new flag) instead of `Install/Upgrade.Remediation{Retries: -1}`. Functionally equivalent for this path (which never relied on remediation firing), but **decouples failed-install retry timing from `Spec.Interval`** the same way the operator change did. `Install.Remediation` / `Upgrade.Remediation` stay nil: retries run through the single `Strategy.RetryInterval` path, matching cozystack-operator's `PackageReconciler`. Reintroducing `Remediation{Retries:-1}` "for safety" would add a second, conflicting retry mechanism and break parity with the operator path. A regression test guards this. (The deployed helm-controller CRD has no rule forbidding a `Strategy` alongside a `Remediation` entry — this is a parity/clarity guard, not a CRD-validation one.) ### Per-Application timeout override is preserved (and extended) The `release.cozystack.io/helm-install-timeout` annotation on `ApplicationDefinition` (`HelmInstallTimeout` in `ReleaseConfig`) still wins over the new global `HelmReleaseInstallTimeout` / `HelmReleaseUpgradeTimeout` defaults when set, applying to **both** `Install.Timeout` and `Upgrade.Timeout`. kubernetes-rd and tenant-rd carry it today (Kamaji bootstrap; seaweedfs-db CNPG bootstrap). A new `release.cozystack.io/helm-upgrade-timeout` annotation overrides **only** `Upgrade.Timeout`, winning over the value the install annotation would otherwise apply — so a kind can carry an asymmetric install/upgrade budget. No `ApplicationDefinition` sets it today, so behavior is unchanged for every existing kind. `Install.Timeout` and `Upgrade.Timeout` are now always populated (from a per-app override or the global default), matching the operator's `buildHelmReleaseSpec`. The previous "stay nil when zero" branch was removed — it was a test shim that kept empty-`ReleaseConfig{}` fixtures green at the cost of api/operator drift. ### Shared validator `parsePositiveDuration` is lifted from `cmd/cozystack-operator/main.go` into `pkg/config` (exported as `ParsePositiveDuration`). Both `cozystack-operator` and `cozystack-api` mains now share one validator with identical reject rules (zero / negative / malformed / empty). The table-driven test moves with it. The annotation parser is shared the same way: `ParseHelmTimeoutAnnotation` validates both the install- and upgrade-timeout annotation values against Flux's unit rules. ## Production safety - Static flag defaults match #2509 exactly. **With stock defaults, every api-generated HR changes shape**: it gains `Strategy.Name=RetryOnFailure` + `RetryInterval`, an explicit `MaxHistory`, and an explicit `Install/Upgrade.Timeout`. This is the intended parity with the operator path, not a no-op. - **Timeout-default change**: because `Install/Upgrade.Timeout` is now always set, the effective install/upgrade timeout for api-generated HRs grows from the implicit flux default (5m, field was previously nil) to the explicit `--helmrelease-{install,upgrade}-timeout` default of `10m`. This is desired — it matches the operator path. - Same intentional retry-cadence change as #2509: failed-release retry cadence on api-generated HRs drops from ~5m (previously coupled to `Spec.Interval`) to 30s (`RetryInterval` default). Healthy-release reconcile cadence is unchanged at 5m. - Per-Application `HelmInstallTimeout` override semantics intact — kubernetes-rd's long Kamaji bootstrap path continues to work; tenant-rd's seaweedfs-db bootstrap budget is unchanged. ## Verification - `go build ./...` clean - `go vet ./...` clean - `go test ./pkg/config/... ./pkg/cmd/server/... ./pkg/registry/apps/application/... ./cmd/cozystack-operator/... ./internal/operator/...` — all pass - New / updated unit tests mirror the operator's spec tests: - `TestConvertApplicationToHelmRelease_BuildsSpecFromConfig` — full HR shape from config (mirrors `TestBuildHelmReleaseSpec`) - `TestConvertApplicationToHelmRelease_ZeroMaxHistory` — `MaxHistory=0` survives as pointer-to-0 (mirrors `TestBuildHelmReleaseSpecZeroMaxHistory`) - `TestConvertApplicationToHelmRelease_PerAppTimeoutOverridesGlobal` — install-annotation override wins over globals (symmetric + asymmetric) - `TestConvertApplicationToHelmRelease_UpgradeTimeoutAnnotation` — upgrade-only override, asymmetric precedence over the install annotation, and the install-sets-both regression guard - `TestConvertApplicationToHelmRelease_AppliesReleaseConfigTimeout` — `Remediation.Retries == -1` assertions replaced with `Strategy.Name == RetryOnFailure` + `Remediation == nil` - `TestParsePositiveDuration` / `TestParseHelmTimeoutAnnotation` — flag and annotation validation, including which error branch fires - Pre-existing test failures in `pkg/apiserver` (randfill panic) and `pkg/lineage` reproduce on `main` without these changes — not introduced here. ## Test plan - [ ] CI E2E install passes with default values (no flags set on cozystack-api Deployment) - [ ] HR objects generated from Application resources in a healthy cluster render with `Strategy.Name=RetryOnFailure` and `RetryInterval=30s` - [ ] kubernetes-rd Application's HR still gets `Install/Upgrade.Timeout=15m` (or whatever its annotation says) — overrides the global default ## Followups (deliberately not bundled) - **Helm chart exposure** — equivalent of #2509's `packages/core/installer/values.yaml` knobs, but for the api server. Touches a different chart (`packages/core/cozystack-api` or wherever the api Deployment lives). Separate PR keeps the diff focused on the Go side. - **Per-Application override of the remaining globals** — interval / retry-interval / max-history have no annotation hook yet; adding them would require new annotations and is out of scope until a real need surfaces. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added server-wide HelmRelease timing flags and defaults (interval, retry interval, install/upgrade timeouts, max history), with per-application timeout overrides. * HelmRelease generation now consistently applies a retry-on-failure strategy with explicit install/upgrade timeouts. * **Bug Fixes** * Stricter validation for duration-related flags to reject malformed, zero, or negative values. * **Tests** * Expanded unit tests for flag parsing/validation, HelmRelease spec generation (including max-history=0 handling), timeout override precedence, and invalid Git ref handling. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
Cozystack
Cozystack is a free platform and framework for building clouds.
Cozystack is a CNCF Sandbox Level Project that was originally built and sponsored by Ænix.
With Cozystack, you can transform a bunch of servers into an intelligent system with a simple REST API for spawning Kubernetes clusters, Database-as-a-Service, virtual machines, load balancers, HTTP caching services, and other services with ease.
Use Cozystack to build your own cloud or provide a cost-effective development environment.
Use-Cases
-
Using Cozystack to build a public cloud
You can use Cozystack as a backend for a public cloud -
Using Cozystack to build a private cloud
You can use Cozystack as a platform to build a private cloud powered by Infrastructure-as-Code approach -
Using Cozystack as a Kubernetes distribution
You can use Cozystack as a Kubernetes distribution for Bare Metal
Documentation
The documentation is located on the cozystack.io website.
Read the Getting Started section for a quick start.
If you encounter any difficulties, start with the troubleshooting guide and work your way through the process that we've outlined.
Versioning
Versioning adheres to the Semantic Versioning principles.
A full list of the available releases is available in the GitHub repository's Release section.
Contributions
Contributions are highly appreciated and very welcomed!
In case of bugs, please check if the issue has already been opened by checking the GitHub Issues section. If it isn't, you can open a new one. A detailed report will help us replicate it, assess it, and work on a fix.
You can express your intention to on the fix on your own. Commits are used to generate the changelog, and their author will be referenced in it.
If you have Feature Requests please use the Discussion's Feature Request section.
Community
You are welcome to join our Telegram group and come to our weekly community meetings. Add them to your Google Calendar or iCal for convenience.
License
Cozystack is licensed under Apache 2.0.
The code is provided as-is with no warranties.
Commercial Support
A list of companies providing commercial support for this project can be found on official site.
