Compare commits

..

91 Commits

Author SHA1 Message Date
Andrei Kvapil
37d59e7ed9 Release v0.37.8 (#1655)
This PR prepares the release `v0.37.8`.
2025-11-25 18:04:06 +01:00
cozystack-bot
ac33585936 Prepare release v0.37.8
Signed-off-by: cozystack-bot <217169706+cozystack-bot@users.noreply.github.com>
2025-11-25 15:58:09 +00:00
Nikita
1676d34e98 Increase strimzi memory limit (#1651)
## What this PR does
Increase strimzi memory limit

### Release note
```release-note
Increased strimzi memory limit
```
2025-11-25 16:50:54 +01:00
Andrei Kvapil
c85e3cfc51 [cozy-lib] Fix malformed ResourceQuota rendering for LoadBalancer services (#1642)
This patch adds special handling for raw Kubernetes ResourceQuota
fields, such as `services.loadbalancers`, preventing them from being
wrapped as `limits.*` or `requests.*` keys by the flatten helper. This
ensures that LoadBalancer quotas render correctly in tenant
specifications.

```release-note
[cozy-lib] Correctly render services.loadbalancers in ResourceQuota without limits.* or requests.* prefixes.
```

<!-- Thank you for making a contribution! Here are some tips for you:
- Start the PR title with the [label] of Cozystack component:
- For system components: [platform], [system], [linstor], [cilium],
[kube-ovn], [dashboard], [cluster-api], etc.
- For managed apps: [apps], [tenant], [kubernetes], [postgres],
[virtual-machine] etc.
- For development and maintenance: [tests], [ci], [docs], [maintenance].
- 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


### Release note

<!--  Write a release note:
- Explain what has changed internally and for users.
- Start with the same [label] as in the PR title
- Follow the guidelines at
https://github.com/kubernetes/community/blob/master/contributors/guide/release-notes.md.
-->

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Refactor**
* Resource flattening now handles compute and quota keys separately:
compute values are sanitized/flattened, quota-like inputs are emitted
directly as plain YAML.

* **Documentation**
* Added in-template comments and clarified examples for resource
processing behavior.

* **New Features**
* CI now runs unit tests; new test targets and test harnesses added
along with a test chart and test cases for quota handling.

<sub>✏️ Tip: You can customize this high-level summary in your review
settings.</sub>
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-11-25 16:50:46 +01:00
Nikita
5271a5c966 [extra] ingress: rm spaces from external ip list (#1652)
## What this PR does
Remove spaces while processing exposed-external-ips list in cozystack
configmap as they 1) are user-specified and 2) lead to an incorrect
resource being created from it.

### Release note
```release-note
Remove spaces while processing exposed-external-ips list in cozystack configmap
```
2025-11-25 16:49:45 +01:00
Andrei Kvapil
0a1ceb6ec6 [Backport release-0.37] scripts: fix 20 migration (#1654)
# Description
Backport of #1653 to `release-0.37`.
2025-11-25 16:48:54 +01:00
nbykov0
b7a809701e scripts: fix 20 migration
Signed-off-by: nbykov0 <166552198+nbykov0@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
(cherry picked from commit ec1a150d2c)
2025-11-25 15:34:13 +00:00
Timofei Larkin
2673ddc352 Release v0.37.7 (#1634)
This PR prepares the release `v0.37.7`.
2025-11-13 21:27:04 +04:00
cozystack-bot
b69b628a69 Prepare release v0.37.7
Signed-off-by: cozystack-bot <217169706+cozystack-bot@users.noreply.github.com>
2025-11-13 16:30:01 +00:00
Timofei Larkin
7a261a3094 [Backport release-0.37] [kubernetes] Cleanup loadbalancer services (#1632)
# Description
Backport of #1631 to `release-0.37`.
2025-11-13 18:21:45 +04:00
Timofei Larkin
309a49d349 [kubernetes] Cleanup loadbalancer services
## What this PR does

Similar to an earlier issue with DataVolumes remaining after deleting
the tenant k8s cluster using them, a similar problem is observed with
LoadBalancer services consuming external IPs. This patch adds another
step to the cleanup Helm hook to delete any such services.

### Release note

```release-note
[kubernetes] Add a cleanup hook to delete LoadBalancer services after
deleting the tenant Kubernetes cluster that they were servicing.
```

Signed-off-by: Timofei Larkin <lllamnyp@gmail.com>
(cherry picked from commit 1651d94291)
2025-11-13 14:17:08 +00:00
Nikita
5d6195f146 [system] kubeovn: increase limits (#1629)
## What this PR does
Increases kube-ovn-cni limits

### Release note
```release-note
Increased kube-ovn-cni limits so that it is not oomkilled during startup on busy nodes.
```

(cherry picked from commit a5c9bfabee)
Signed-off-by: Timofei Larkin <lllamnyp@gmail.com>
2025-11-13 16:38:45 +03:00
Andrei Kvapil
2878fd1491 [Backport release-0.37] [rbac] Fix permissions for high-privilege users (#1624)
# Description
Backport of #1622 to `release-0.37`.
2025-11-12 09:57:06 -05:00
Timofei Larkin
ff89f4c390 [rbac] Fix permissions for high-privilege users
## What this PR does

This patch grants "admin" permissions to super-admins, "use" permissions
to admins and super-admins, "view" permissions to "use"-privileged
users, admins, and super-admins. Previously lower-privileged roles were
not assigned to higher-privileged users, so a viewer could excercise
their basic read-only permissions which were not available to
high-privilege users. This patch corrects the template function used to
generate subjects in rolebindings, fixing the issue.

### Release note

```release-note
[rbac] Fix issue of privileged users not having low-privilege read-only
permissions.
```

Signed-off-by: Timofei Larkin <lllamnyp@gmail.com>
(cherry picked from commit 7ddd9cf4a8)
2025-11-12 14:46:29 +00:00
Andrei Kvapil
ea043bc735 Release v0.37.6 (#1616)
This PR prepares the release `v0.37.6`.
2025-11-07 23:44:07 +01:00
cozystack-bot
b5984e764b Prepare release v0.37.6
Signed-off-by: cozystack-bot <217169706+cozystack-bot@users.noreply.github.com>
2025-11-07 22:00:21 +00:00
Andrei Kvapil
ad117ecf5a [cozystack-controller] improve API tests
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
2025-11-07 22:54:45 +01:00
Timofei Larkin
cd3ea570da [api,lineage] Ensure node-local traffic
Since 0.37, many requests to the k8s API now go through a mutating
webhook (lineage-controller-webhook). Since the lineage webhook makes
multiple requests to the k8s API and, indirectly, to the Cozystack API
server, each request for, e.g., creating a secret now causes a lot of
chatter between the webhook, the k8s API, and the Cozystack API. When
this happens cross-node or, worse yet, cross-zone, this can blow up the
latency for simple requests.

This patch changes the Cozystack API to a DaemonSet targetting
controlplane nodes, configures its service for an `Local` internal
traffic policy and adds environment variables indicating that the k8s
API server is to be found at <hostIP>:6443, **not only for the Cozystack
API, but also for the lineage-controller-webhook.** This is a valid
configuration in most scenarios, including the default installation
method on top of Talos Linux in Cozystack, however, if this is not valid
in your environment, you must now set the values
`.lineageControllerWebhook.localK8sAPIEndpoint.enabled` and
`.cozystackAPI.localK8sAPIEndpoint.enabled` to `false` in the respective
system Helm releases.

```release-note
[api,lineage] Configure all chatter between the Lineage webhook, the
Cozystack API server and the Kubernetes API server to be confined to a
single controlplane node, improving k8s API latency.
```

Signed-off-by: Timofei Larkin <lllamnyp@gmail.com>
2025-11-07 22:54:28 +01:00
Andrei Kvapil
7ad74f04c6 [dashboard-controller] Fix static resources reconciliation and showing
secrets

Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
2025-11-07 17:29:59 +01:00
Andrei Kvapil
4cbf562ae6 [virtual-machine] Revert per-vm network policies (#1611)
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>

<!-- Thank you for making a contribution! Here are some tips for you:
- Start the PR title with the [label] of Cozystack component:
- For system components: [platform], [system], [linstor], [cilium],
[kube-ovn], [dashboard], [cluster-api], etc.
- For managed apps: [apps], [tenant], [kubernetes], [postgres],
[virtual-machine] etc.
- For development and maintenance: [tests], [ci], [docs], [maintenance].
- 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

Revert per-vm network policies functionality introduced by
https://github.com/cozystack/cozystack/pull/1611
As it is not working as expected any way.

This is temporary solution before implementing full-fledged security
groups in Cozystack

fixes https://github.com/cozystack/cozystack/issues/1601
alternative solution: https://github.com/cozystack/cozystack/pull/1602

### Release note

<!--  Write a release note:
- Explain what has changed internally and for users.
- Start with the same [label] as in the PR title
- Follow the guidelines at
https://github.com/kubernetes/community/blob/master/contributors/guide/release-notes.md.
-->

```release-note
[virtual-machine] Revert per-vm network policies
```
2025-11-07 16:58:57 +01:00
Andrei Kvapil
d8c45db075 [cozystack-api][dashboard] Fix filtering for application services/ingresses/secrets (#1612)
<!-- Thank you for making a contribution! Here are some tips for you:
- Start the PR title with the [label] of Cozystack component:
- For system components: [platform], [system], [linstor], [cilium],
[kube-ovn], [dashboard], [cluster-api], etc.
- For managed apps: [apps], [tenant], [kubernetes], [postgres],
[virtual-machine] etc.
- For development and maintenance: [tests], [ci], [docs], [maintenance].
- 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

- **[dashboard-controller] Fix labelSelectors**
- **[cozystack-api] Enhance TenantSecrets filtering**
- **[cozystack-api] Fix sorting for TenantSecrets**

### Release note

<!--  Write a release note:
- Explain what has changed internally and for users.
- Start with the same [label] as in the PR title
- Follow the guidelines at
https://github.com/kubernetes/community/blob/master/contributors/guide/release-notes.md.
-->

```release-note
[cozystack-api][dashboard] Fix filtering for application services/ingresses/secrets
```

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Refactor**
* Standardized internal configuration naming conventions across
dashboard components.
* Enhanced tenant secret validation and filtering logic with improved
label-based operations for consistency and correctness.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-11-07 16:58:52 +01:00
Andrei Kvapil
625f35d66f [dashboard] sync with upstream & enhancements (#1603)
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>

<!-- Thank you for making a contribution! Here are some tips for you:
- Start the PR title with the [label] of Cozystack component:
- For system components: [platform], [system], [linstor], [cilium],
[kube-ovn], [dashboard], [cluster-api], etc.
- For managed apps: [apps], [tenant], [kubernetes], [postgres],
[virtual-machine] etc.
- For development and maintenance: [tests], [ci], [docs], [maintenance].
- 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.
-->

- Move patches to upstream: `namespaces` and `hide inside`
- Introduce flatMap logic
- Remove `tenantsecretstables` resource
- Extend dashboard-controller to specify `multilineString` for any
string without enum in spec (previusly it was for all strings)

<!--  Write a release note:
- Explain what has changed internally and for users.
- Start with the same [label] as in the PR title
- Follow the guidelines at
https://github.com/kubernetes/community/blob/master/contributors/guide/release-notes.md.
-->

```release-note
[dashboard] sync with upstream & enhancements
```

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

* **New Features**
* Enhanced OpenAPI form handling: string fields now better support
multiline input.

* **Improvements**
* Secrets UI and API alignment: secrets display and data keys updated
for consistency.
  * Form generation improved for nested objects and arrays.
* Deployment defaults adjusted (logger flags normalized; inside feature
hidden via env).

* **Removed**
* Removed the "Inside" header menu item and the legacy secrets-table
API/resource.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-11-07 16:58:40 +01:00
Timofei Larkin
4b395d758e [api] Use shared informer cache (#1539)
## What this PR does

This patch changes all clients in the Cozystack API server to typed ones
from the controller runtime. This should improve the performance of the
API server and simplifies the code by removing work with unstructured
objects and dynamic clients.

### Release note

```release-note
[api] Use typed and cache-backed k8s clients in the Cozystack API to
improve performance. Get rid of operations on unstructured objects and
use of dynamic clients.
```

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Refactor**
* Backend migrated to a controller-runtime manager with typed clients
for Kubernetes resources, improving watch reliability and cache sync.
* Storage paths for applications, tenant modules, namespaces, and
secrets now use strongly-typed resource handling for more consistent
behavior.

* **Chores**
  * Cluster role expanded to include services in core API permissions.

* **Notes**
  * No user-facing API schema changes.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-11-07 16:52:52 +01:00
Timofei Larkin
c1ac876ff7 [dashboard] Revert reconciler removal (#1559)
## What this PR does

In a previous patch (#1555) the reconciliation loop for the OpenAPI UI
resources was accidentally removed. This patch reintroduces a separate
controller, which handles updates to CozystackResourceDefinitions and
creates, updates, or deletes the dashboard's custom resources.

### Release note

```release-note
[dashboard] Reintroduce the accidentally removed reconciler that
autoconfigures custom dashboard resources for the OpenAPI UI.
```
2025-11-07 16:43:51 +01:00
Timofei Larkin
8d91fcddd4 [controller] Remove crdmem, handle DaemonSet (#1555)
This patch drops the custom caching of the Cozystack resource
definitions in favor of the informer cache and adds a flag to the
Cozystack controller to select, whether it restarts the cozystack-api
deployment or the cozystack-api daemonset.

As with the new default behavior of using a local endpoint for the k8s
API by the lineage webhook and the Cozystack API, the Cozystack
controller now also defaults to restarting a Cozystack API DaemonSet
instead of a Deployment. To revert to the old behavior, disable the
local k8s API endpoint on the webhook and cozystack API and set the
`cozystackController.cozystackAPIKind` value in the Cozystack controller
system Helm chart to "Deployment".

```release-note
[controller] Use informer cache instead of the older bespoke
implementation and add support for running the Cozystack API as a
DaemonSet.
```
2025-11-07 16:20:04 +01:00
Andrei Kvapil
84f55fa728 [Backport release-0.37] [cozy-lib] Fix: handling resources=nil (#1610)
# Description
Backport of #1607 to `release-0.37`.
2025-11-07 11:03:55 +01:00
Andrei Kvapil
fbec0a1064 [Backport release-0.37] [kubernetes] Helm hooks for cleanup (#1609)
# Description
Backport of #1606 to `release-0.37`.
2025-11-07 11:03:45 +01:00
Andrei Kvapil
b7e7b0ac54 [cozy-lib] Fix: handling resources=nil
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
Co-authored-by: Timofei Larkin <lllamnyp@gmail.com>
(cherry picked from commit 00328c8a31)
2025-11-07 10:03:42 +00:00
Timofei Larkin
edbccafd49 [kubernetes] Helm hooks for cleanup
## What this PR does

When deleting a Kubernetes, some resources may linger post deletion
because of a race to remove HelmReleases deployed inside the tenant
cluster and the removal of the cluster and its controlplane itself. This
patch modifies the existing pre-delete hook to remove those helmreleases
instead of simply suspending them. Similarly, datavolumes may also
remain. These are now delete with a post-delete hook.

### Release note

```release-note
[kubernetes] Use Helm hooks to clean up HelmReleases deployed in tenant
clusters and DataVolumes backing the tenant clusters' PVCs when deleting
a tenant Kubernetes.
```

Signed-off-by: Timofei Larkin <lllamnyp@gmail.com>
(cherry picked from commit 63db8ca009)
2025-11-07 09:51:05 +00:00
Andrei Kvapil
e7d30df251 [Backport release-0.37] [nats] Fix NATS app chart to use existing secret credentials when present (#1605)
# Description
Backport of #1599 to `release-0.37`.
2025-11-07 09:25:46 +01:00
Isaiah Olson
3a1a69e10b Use dig function to check for existing secret in NATS app template and prevent nil indexing
Signed-off-by: Isaiah Olson <isaiah@olson-network.com>
(cherry picked from commit 627022972d)
2025-11-06 10:11:15 +00:00
Isaiah Olson
46c1116f07 Fix NATS app chart to use existing secret credentials when present
Signed-off-by: Isaiah Olson <isaiah@olson-network.com>
(cherry picked from commit 1e8a9ee980)
2025-11-06 10:11:15 +00:00
Andrei Kvapil
c1f056ff4e Release v0.37.5 (#1595)
This PR prepares the release `v0.37.5`.
2025-11-04 18:55:09 +01:00
cozystack-bot
181fc3cc40 Prepare release v0.37.5
Signed-off-by: cozystack-bot <217169706+cozystack-bot@users.noreply.github.com>
2025-11-04 17:19:31 +00:00
Andrei Kvapil
3d403205ca [Backport release-0.37] [dashboard-controller] Move bages generation logic to internal dashboard component (#1593)
# Description
Backport of #1567 to `release-0.37`.
2025-11-04 17:37:00 +01:00
Andrei Kvapil
3b027a7da9 [dashboard-controller] Move bages generation logic to internal dashboard
component

Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
(cherry picked from commit af460f1c41)
2025-11-04 16:36:43 +00:00
Andrei Kvapil
68718b9bf4 [Backport release-0.37] [nats] Fixes for NATS App Helm chart, fix template issues with config.merge (#1591)
# Description
Backport of #1583 to `release-0.37`.
2025-11-04 17:20:08 +01:00
Andrei Kvapil
32b12ceefa [Backport release-0.37] [flux] Close Flux Operator ports to external access (#1592)
# Description
Backport of #1581 to `release-0.37`.
2025-11-04 17:18:42 +01:00
IvanHunters
c1ec2a2fc3 add rule for success installing
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
(cherry picked from commit 48c6e23ca0)
2025-11-04 16:13:55 +00:00
IvanHunters
71c32d91a7 add patch
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
(cherry picked from commit f60e2555c9)
2025-11-04 16:13:55 +00:00
IvanHunters
65ea7116ce close metrics port for external
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
(cherry picked from commit 52a23eacfc)
2025-11-04 16:13:55 +00:00
IvanHunters
d7b5636f23 [flux] Close Flux Operator ports to external access
This patch updates the Flux Operator Deployment to remove hostPort and hostNetwork,
ensuring that ports 8080 and 8081 are only accessible within the cluster.
This prevents external exposure and improves security.

```release-note
[flux] Close Flux Operator ports (8080/8081) to external access for improved security.
```

Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
(cherry picked from commit eea685065a)
2025-11-04 16:13:55 +00:00
Timofei Larkin
b0beb6edf9 [nats] Terser checks using with
This patch makes the fixes from `b1ebc9cc` by @insignia96 terser by
making use of Helm's `with` blocks.

Signed-off-by: Timofei Larkin <lllamnyp@gmail.com>
(cherry picked from commit 172774b6cd)
2025-11-04 16:00:28 +00:00
Isaiah Olson
7058e404cf Fixes for NATS App Helm chart, fix template issues with config.merge value
Signed-off-by: Isaiah Olson <isaiah@olson-network.com>
(cherry picked from commit b1ebc9cc85)
2025-11-04 16:00:28 +00:00
Nikita
25edc1f54b [core] rm talos lldp extension (#1586)
<!-- Thank you for making a contribution! Here are some tips for you:
- Start the PR title with the [label] of Cozystack component:
- For system components: [platform], [system], [linstor], [cilium],
[kube-ovn], [dashboard], [cluster-api], etc.
- For managed apps: [apps], [tenant], [kubernetes], [postgres],
[virtual-machine] etc.
- For development and maintenance: [tests], [ci], [docs], [maintenance].
- 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.
-->

Removes Talos lldp extension. Please build a custom talos image with factory.talos.dev if you need it.

<!--  Write a release note:
- Explain what has changed internally and for users.
- Start with the same [label] as in the PR title
- Follow the guidelines at
https://github.com/kubernetes/community/blob/master/contributors/guide/release-notes.md.
-->

```release-note
Talos lldp extension removed.
```

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

* **Chores**
* Removed LLDPD (Link Layer Discovery Protocol Daemon) system extension
from cluster configuration. This eliminates the LLDPD kernel module from
cluster setups, removes LLDPD references from build processes, and
updates installation profiles across all supported deployment methods
including bare metal, cloud environments, and ISO installations,
resulting in a reduced system footprint.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-11-04 13:48:22 +01:00
Andrei Kvapil
36a52277f6 [Backport release-0.37] [kubevirt] Fix: kubevirt metrics rule (#1588)
# Description
Backport of #1584 to `release-0.37`.
2025-11-04 13:43:46 +01:00
Andrei Kvapil
0e5aad8588 [kubevirt] Fix: kubevirt metrics rule
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
(cherry picked from commit 6443a1264e)
2025-11-04 12:35:02 +00:00
Andrei Kvapil
70cb6b586a [redis] Bump Redis image version for security fixes (#1580)
This patch updates the RedisFailover Helm template to use a newer,
secure Redis version (8.2.0). This addresses known security issues in
the previous Redis version and ensures safer deployments.

```release-note
[redis] Upgrade Redis to a secure version (8.2.0) to fix security vulnerabilities.
```

<!-- Thank you for making a contribution! Here are some tips for you:
- Start the PR title with the [label] of Cozystack component:
- For system components: [platform], [system], [linstor], [cilium],
[kube-ovn], [dashboard], [cluster-api], etc.
- For managed apps: [apps], [tenant], [kubernetes], [postgres],
[virtual-machine] etc.
- For development and maintenance: [tests], [ci], [docs], [maintenance].
- 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


### Release note

<!--  Write a release note:
- Explain what has changed internally and for users.
- Start with the same [label] as in the PR title
- Follow the guidelines at
https://github.com/kubernetes/community/blob/master/contributors/guide/release-notes.md.
-->


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Redis deployments can now specify the container image via a new
configurable value (default: redis:8.2.0), allowing easy override of the
Redis image used.
* **Schema**
* Values schema and resource definition schemas updated to include and
validate the new image setting.
* **Documentation**
  * README updated to document the new image parameter.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-11-04 10:27:38 +01:00
Andrei Kvapil
90b29c7d4d [Backport release-0.37] [ingress] Enforce HTTPS-only for API (#1585)
# Description
Backport of #1582 to `release-0.37`.
2025-11-04 10:26:17 +01:00
IvanHunters
82e5a0d403 [ingress] Enforce HTTPS-only for API
This patch updates the default API Ingress to add the
nginx.ingress.kubernetes.io/force-ssl-redirect annotation,
ensuring all HTTP traffic (port 80) is redirected to HTTPS (port 443).
This prevents unencrypted external access and improves security.

```release-note
[ingress] Force HTTPS access for api.dev3.infra.aenix.org and block direct HTTP.
```

Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
(cherry picked from commit 667c778f27)
2025-11-04 09:18:47 +00:00
Andrei Kvapil
520cfd2526 Release v0.37.4 (#1578)
This PR prepares the release `v0.37.4`.
2025-11-03 13:41:08 +01:00
cozystack-bot
39db2c141a Prepare release v0.37.4
Signed-off-by: cozystack-bot <217169706+cozystack-bot@users.noreply.github.com>
2025-11-03 11:03:59 +00:00
Andrei Kvapil
42c94cfebd [Backport release-0.37] [tenant] Allow listing workloads (#1577)
# Description
Backport of #1576 to `release-0.37`.
2025-11-03 11:58:05 +01:00
Andrei Kvapil
9fae1b17b8 [tenant] Allow listing workloads
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
(cherry picked from commit 93a9241899)
2025-11-03 10:57:22 +00:00
Andrei Kvapil
5d232bef97 [Backport release-0.37] [seaweedfs] Fix migration to v3.99 (#1575)
# Description
Backport of #1572 to `release-0.37`.
2025-11-03 11:33:42 +01:00
Andrei Kvapil
19d2f43bf5 [Backport release-0.37] [nats] Merge container spec, not podTemplate (#1574)
# Description
Backport of #1571 to `release-0.37`.
2025-11-03 11:33:30 +01:00
Andrei Kvapil
7f646d84bb [seaweedfs] Fix migration to v3.99
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
(cherry picked from commit 42e6f0e3f2)
2025-11-03 10:33:28 +00:00
Timofei Larkin
83505f50c7 [nats] Merge container spec, not podTemplate
## What this PR does

The NATS chart incorrectly used podTemplate+merge instead of
container+merge to add resource requests and limits to the NATS
container in the statefulset, but as a result it just completely wiped
out the default container spec. By moving the overrides under the
container key, the upstream chart now correctly merges the resource
requests, instead of overwriting the container spec.

### Release note

```release-note
[nats] Fix incorrect path to container resources in the NATS chart.
```

Signed-off-by: Timofei Larkin <lllamnyp@gmail.com>
(cherry picked from commit 8b95db06ee)
2025-11-03 10:33:14 +00:00
Andrei Kvapil
46de1f311b [Backport release-0.37] [e2e] Increase Kubernetes connection timeouts (#1573)
# Description
Backport of #1570 to `release-0.37`.
2025-11-03 10:48:38 +01:00
IvanHunters
682a933156 [e2e] Increase Kubernetes connection timeouts
This patch increases the connection and request timeouts used in the
E2E tests when communicating with the Kubernetes API. The change improves
test stability under high load and slow cluster response conditions.

```release-note
[e2e] Increase connection and request timeouts for Kubernetes API calls in E2E tests to improve stability.
```

Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
(cherry picked from commit e2eb1e267b)
2025-11-03 09:48:21 +00:00
Andrei Kvapil
6d402ecff9 Release v0.37.3 (#1566)
This PR prepares the release `v0.37.3`.
2025-11-01 03:23:25 +05:00
cozystack-bot
2cb80079d1 Prepare release v0.37.3
Signed-off-by: cozystack-bot <217169706+cozystack-bot@users.noreply.github.com>
2025-10-31 20:39:20 +00:00
Andrei Kvapil
b8604b8ec5 [seaweedfs] Update SeaweedFS v3.99 and deploy S3 as stacked service (#1562)
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>

<!-- Thank you for making a contribution! Here are some tips for you:
- Start the PR title with the [label] of Cozystack component:
- For system components: [platform], [system], [linstor], [cilium],
[kube-ovn], [dashboard], [cluster-api], etc.
- For managed apps: [apps], [tenant], [kubernetes], [postgres],
[virtual-machine] etc.
- For development and maintenance: [tests], [ci], [docs], [maintenance].
- 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


### Release note

<!--  Write a release note:
- Explain what has changed internally and for users.
- Start with the same [label] 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**
* Helm values now control ingress paths; computed cluster endpoint env
vars are injected.
  * Optional container securityContext for volume init containers added.
  * Node architecture-specific targeting disabled by default.

* **Refactor**
* Image configuration reorganized with separate registry field;
container image build simplified.

* **Bug Fixes / Behavior**
* S3-related authorization and signature handling changed; S3 gateway
toggled.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-10-31 21:24:13 +01:00
Andrei Kvapil
f645a5d8fc Update LINSTOR v1.32.3 (#1565)
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>

<!-- Thank you for making a contribution! Here are some tips for you:
- Start the PR title with the [label] of Cozystack component:
- For system components: [platform], [system], [linstor], [cilium],
[kube-ovn], [dashboard], [cluster-api], etc.
- For managed apps: [apps], [tenant], [kubernetes], [postgres],
[virtual-machine] etc.
- For development and maintenance: [tests], [ci], [docs], [maintenance].
- 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


### Release note

<!--  Write a release note:
- Explain what has changed internally and for users.
- Start with the same [label] as in the PR title
- Follow the guidelines at
https://github.com/kubernetes/community/blob/master/contributors/guide/release-notes.md.
-->

```release-note
Update LINSTOR v1.32.3
```
2025-10-31 21:22:30 +01:00
Timofei Larkin
31d87671a1 [system] kube-ovn: turn off enableLb (#1548)
<!-- Thank you for making a contribution! Here are some tips for you:
- Start the PR title with the [label] of Cozystack component:
- For system components: [platform], [system], [linstor], [cilium],
[kube-ovn], [dashboard], [cluster-api], etc.
- For managed apps: [apps], [tenant], [kubernetes], [postgres],
[virtual-machine] etc.
- For development and maintenance: [tests], [ci], [docs], [maintenance].
- 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
Turns off kubeovn enableLb, kube-proxy implementation of kube-ovn.

### Release note

<!--  Write a release note:
- Explain what has changed internally and for users.
- Start with the same [label] as in the PR title
- Follow the guidelines at
https://github.com/kubernetes/community/blob/master/contributors/guide/release-notes.md.
-->

```release-note
[system] kube-ovn: turn off kube-proxy implementation
```

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Chores**
* Added a new load balancing configuration option to system settings
(disabled by default).

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-10-31 18:27:31 +01:00
Timofei Larkin
13b294c9a7 [redis-operator] Build patched operator in-tree (#1547)
## What this PR does

This patch moves the build of the Redis operator into the Cozystack
organization and patches it to prevent overwriting third-party labels on
owned resources.

### Release note

```release-note
[redis-operator] Move operator into tree and patch it to retain
third-party labels on owned resources, reducing noisy traffic to the API
server.
```

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Chores**
* Implemented automated Docker image build pipeline with version
tracking and caching.
* Updated image configuration to include repository reference and digest
for reproducibility.

* **Bug Fixes**
* Improved label and annotation handling to preserve existing Kubernetes
resource metadata instead of overwriting it.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-10-31 18:26:31 +01:00
Andrei Kvapil
2ee2bf55ed [velero] Set defaultItemOperationTimeout=24h (#1542)
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>

<!-- Thank you for making a contribution! Here are some tips for you:
- Start the PR title with the [label] of Cozystack component:
- For system components: [platform], [system], [linstor], [cilium],
[kube-ovn], [dashboard], [cluster-api], etc.
- For managed apps: [apps], [tenant], [kubernetes], [postgres],
[virtual-machine] etc.
- For development and maintenance: [tests], [ci], [docs], [maintenance].
- 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

This PR changes default timeout for Velero to copy single item. Default
value 4h is not enough for copying large block volumes of virtual
machines.

### Release note

<!--  Write a release note:
- Explain what has changed internally and for users.
- Start with the same [label] as in the PR title
- Follow the guidelines at
https://github.com/kubernetes/community/blob/master/contributors/guide/release-notes.md.
-->

```release-note
[velero] Set defaultItemOperationTimeout=24h
```

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Chores**
* Extended default operation timeout to 24 hours to provide increased
time for operations to complete.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-10-31 18:25:31 +01:00
Andrei Kvapil
39f51f7fba [dashboard] Update openapi-ui v1.0.3 + fixes (#1564)
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>

<!-- Thank you for making a contribution! Here are some tips for you:
- Start the PR title with the [label] of Cozystack component:
- For system components: [platform], [system], [linstor], [cilium],
[kube-ovn], [dashboard], [cluster-api], etc.
- For managed apps: [apps], [tenant], [kubernetes], [postgres],
[virtual-machine] etc.
- For development and maintenance: [tests], [ci], [docs], [maintenance].
- 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.
-->

- Update openapi-ui to v1.0.3
- Show YAML editor as readonly in YAML tab
- Remove inside link from user menu
- fix editing for tenantmodules, fixes
https://github.com/cozystack/cozystack/issues/1550
- fix editing valuesOverride, fixes
https://github.com/cozystack/cozystack/issues/1560

<!--  Write a release note:
- Explain what has changed internally and for users.
- Start with the same [label] as in the PR title
- Follow the guidelines at
https://github.com/kubernetes/community/blob/master/contributors/guide/release-notes.md.
-->

```release-note
[dashboard] Update openapi-ui v1.0.3 + fixes
```

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

* **Bug Fixes**
* Made YAML editor read-only to prevent accidental modifications in
details view
  * Fixed API request header handling to prevent stream abort issues
  * Updated resource API endpoint paths for correct data retrieval
  * Removed menu navigation item from user interface
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-10-31 18:21:09 +01:00
Timofei Larkin
0c50253e2c [kubernetes] Use controlPlane.replicas field (#1556)
## What this PR does

The managed Kubernetes app accepts a .controPlane.replicas field, but
this value was never used, instead being hardcoded in the
KamajiControlPlane template to 2. This patch fixes this.

### Release note

```release-note
[kubernetes] Pass the .controlPlane.replicas field into the
KamajiControlPlane template, making the replica count of the
controlplane pods user-configurable.
```

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Control plane replica count is now configurable via Helm values,
allowing flexible deployment scaling.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-10-31 18:18:57 +01:00
Andrei Kvapil
cfab053c66 [mariadb-operator] Add post-delete job to remove PVCs (#1553)
<!-- Thank you for making a contribution! Here are some tips for you:
- Start the PR title with the [label] of Cozystack component:
- For system components: [platform], [system], [linstor], [cilium],
[kube-ovn], [dashboard], [cluster-api], etc.
- For managed apps: [apps], [tenant], [kubernetes], [postgres],
[virtual-machine] etc.
- For development and maintenance: [tests], [ci], [docs], [maintenance].
- 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

[mariadb-operator] Add post-delete job to remove PVCs
This patch adds a Helm post-delete hook job that removes
PersistentVolumeClaims
left behind after Helm release deletion. The MariaDB Operator currently
does not
handle PVC cleanup, so this job ensures proper resource removal.

### Release note

<!--  Write a release note:
- Explain what has changed internally and for users.
- Start with the same [label] as in the PR title
- Follow the guidelines at
https://github.com/kubernetes/community/blob/master/contributors/guide/release-notes.md.
-->

```release-note
[mariadb-operator] Add a post-delete hook job to clean up PVCs left after Helm release deletion.
```

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Persistent storage volumes are now automatically cleaned up when the
MySQL application is deleted, preventing orphaned storage resources from
accumulating in your cluster.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-10-31 18:14:01 +01:00
Andrei Kvapil
67a8fa91e8 [seaweedfs] Allow users to discover their buckets (#1528)
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>

<!-- Thank you for making a contribution! Here are some tips for you:
- Start the PR title with the [label] of Cozystack component:
- For system components: [platform], [system], [linstor], [cilium],
[kube-ovn], [dashboard], [cluster-api], etc.
- For managed apps: [apps], [tenant], [kubernetes], [postgres],
[virtual-machine] etc.
- For development and maintenance: [tests], [ci], [docs], [maintenance].
- 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

This PR enables building of `seaweedfs` image.
Also backports patch from upstream
https://github.com/seaweedfs/seaweedfs/pull/7335

### Release note

<!--  Write a release note:
- Explain what has changed internally and for users.
- Start with the same [label] as in the PR title
- Follow the guidelines at
https://github.com/kubernetes/community/blob/master/contributors/guide/release-notes.md.
-->

```release-note
[seaweedfs] Allow users to discover their buckets
```

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* S3 signature handling adjusted so signature verification focuses on
authentication; permission checks are evaluated afterward.

* **Chores**
* Build process now discovers and uses remote release versions
dynamically.
* Introduced an optimized multi-stage container build with improved
tagging and registry caching.
* Added configurable image settings (global image name and image tag)
for deployment.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-10-31 18:13:31 +01:00
Timofei Larkin
5703e16a80 [monitoring] add settings alert for slack (#1545)
**What this PR does**
This PR adds configuration for sending alerts from Alerta to Slack.

**Key changes**
Added Slack integration configuration in Alerta settings.
2025-10-31 18:12:37 +01:00
Andrei Kvapil
297ddf853b [Backport release-0.37] [kamaji] Respect 3rd party labels (#1534)
# Description
Backport of #1531 to `release-0.37`.
2025-10-21 15:05:55 +02:00
Timofei Larkin
62f80f85b4 [kamaji] Respect 3rd party labels
The Kamaji controller overwrites labels on many of the resources it owns
(clastix/kamaji#991). This change applies PR clastix/kamaji#992 to
Cozystack's build of Kamaji, so the lineage webhook doesn't fight the
Kamaji controller, causing a non-stop reconciliation loop.

```release-note
[kamaji] Do not clobber third party labels on resources controlled by
Kamaji.
```

Signed-off-by: Timofei Larkin <lllamnyp@gmail.com>
(cherry picked from commit b858745cdd)
2025-10-17 15:49:14 +00:00
Timofei Larkin
a5cdaddbb4 [lineage] Check for nil chart in HelmRelease (#1525)
## What this PR does

Some HelmReleases use `chartRef` instead of `chart`. If the lineage
webhook finds such a HelmRelease, a nil pointer dereference happens.
This patch adds a nil check to guard against this.

### Release note

```release-note
[lineage] Add a nil check to guard against HelmReleases with a nil
.spec.chart field when traversing the ownership tree.
```

(cherry picked from commit d57f9acc7a)
Signed-off-by: Timofei Larkin <lllamnyp@gmail.com>
2025-10-16 17:19:19 +03:00
Timofei Larkin
0e4fe7a33e [dashboard] Show service LB IP (#1524)
Fix an incorrect JSON path that prevented Service LoadBalancer IPs from
rendering in the table view.

(cherry picked from commit 466f0fed52)
Signed-off-by: Timofei Larkin <lllamnyp@gmail.com>
2025-10-16 17:19:13 +03:00
Timofei Larkin
ee95353342 [apps] Make VM service user facing (#1523)
(cherry picked from commit c1edc5d711)
Signed-off-by: Timofei Larkin <lllamnyp@gmail.com>
2025-10-16 17:19:04 +03:00
Andrei Kvapil
9506c58926 Release v0.37.2 (#1520)
This PR prepares the release `v0.37.2`.
2025-10-15 14:08:07 +02:00
cozystack-bot
ffcc55c588 Prepare release v0.37.2
Signed-off-by: cozystack-bot <217169706+cozystack-bot@users.noreply.github.com>
2025-10-15 10:56:27 +00:00
Andrei Kvapil
cbf67cd30e [Backport release-0.37] [platform] Better migration for 0.36.2->0.37.2+ (#1522)
# Description
Backport of #1521 to `release-0.37`.
2025-10-15 12:50:36 +02:00
Timofei Larkin
1b46ff3f6b [platform] Better migration for 0.36.2->0.37.2+
For users upgrading from 0.36.2 directly to 0.37.2+, where the
lineage-controller-webhook is broken out of the Cozystack controller
into a separate daemonset, the existing migration script of 0.36->0.37.0
is insufficient. This patch ensures the presence of the new version of
the lineage webhook and fixes a bug in the migration script where the
readiness of the webhook was not appropriately verified.

```release-note
[platform] Improved migration script when skipping versions 0.37.0 and
0.37.1 during upgrades.
```

Signed-off-by: Timofei Larkin <lllamnyp@gmail.com>
(cherry picked from commit bf1ece5f7c)
2025-10-15 10:50:02 +00:00
Timofei Larkin
674b3963a7 [lineage] Separate webhook from cozy controller (#1515)
## What this PR does

The lineage-controller-webhook makes a lot of outgoing API calls for
every event it handles, contributing to a high API server latency,
increasing the number of in-flight requests and generally degrading
performance. This patch remedies this by separating the lineage
component from the cozystack-controller and deploying it as a separate
component on all control-plane nodes. Additionally, a new internal label
is introduced to track if a resource has already been handled by the
webhook. This label is used to exclude such resources from
consideration. Addresses #1513.

### Release note

```release-note
[lineage] Break webhook out into a separate daemonset. Reduce
unnecessary webhook calls by marking handled resources and excluding
them from consideration by the webhook's object selector.
```

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Standalone Lineage Controller Webhook deployed as its own DaemonSet
with a dedicated Helm chart and image build targets.
  - Dedicated TLS provisioning for the webhook via chart-managed certs.

- **Changes**
  - Main controller no longer hosts webhook endpoints or certificates.
- Webhook now excludes already-managed resources to reduce unnecessary
invocations.
  - Platform bundles updated to include the new webhook release.

- **Documentation**
  - Changelog updated to reflect the separation and optimization.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-10-15 12:49:02 +02:00
Andrei Kvapil
f71f914fe6 [Backport release-0.37] [api] Fix listing tenantnamespaces for non-oidc users (#1519)
# Description
Backport of #1517 to `release-0.37`.
2025-10-15 10:10:46 +02:00
Andrei Kvapil
a09ed799e9 [api] Fix listing tenantnamespaces for non-oidc users
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
(cherry picked from commit 671e13df70)
2025-10-15 08:10:29 +00:00
Andrei Kvapil
8e35d6ae4e Release v0.37.1 (#1512)
This PR prepares the release `v0.37.1`.
2025-10-13 16:04:33 +02:00
cozystack-bot
2f8c6b72fe Prepare release v0.37.1
Signed-off-by: cozystack-bot <217169706+cozystack-bot@users.noreply.github.com>
2025-10-13 13:29:01 +00:00
Andrei Kvapil
5a679e12ad [api] Fix RBAC for listing of TenantNamespaces and handle system:masters (#1511)
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>

<!-- Thank you for making a contribution! Here are some tips for you:
- Start the PR title with the [label] of Cozystack component:
- For system components: [platform], [system], [linstor], [cilium],
[kube-ovn], [dashboard], [cluster-api], etc.
- For managed apps: [apps], [tenant], [kubernetes], [postgres],
[virtual-machine] etc.
- For development and maintenance: [tests], [ci], [docs], [maintenance].
- 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

Fix regression introduced by
https://github.com/cozystack/cozystack/pull/1507

### Release note

<!--  Write a release note:
- Explain what has changed internally and for users.
- Start with the same [label] as in the PR title
- Follow the guidelines at
https://github.com/kubernetes/community/blob/master/contributors/guide/release-notes.md.
-->

```release-note
[api] Fix RBAC for listing of TenantNamespaces and handle system:masters
```

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- New Features
- System-wide administrators now see all tenant namespaces without
filtering.
- Expanded read access for role bindings to improve visibility of access
configurations.

- Bug Fixes
- Resolved cases where some authorized admins could not view all tenant
namespaces due to RBAC filtering.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-10-13 15:21:05 +02:00
Andrei Kvapil
0176ba5e95 [dashboard] Fix logout (#1510)
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>

<!-- Thank you for making a contribution! Here are some tips for you:
- Start the PR title with the [label] of Cozystack component:
- For system components: [platform], [system], [linstor], [cilium],
[kube-ovn], [dashboard], [cluster-api], etc.
- For managed apps: [apps], [tenant], [kubernetes], [postgres],
[virtual-machine] etc.
- For development and maintenance: [tests], [ci], [docs], [maintenance].
- 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


### Release note

<!--  Write a release note:
- Explain what has changed internally and for users.
- Start with the same [label] as in the PR title
- Follow the guidelines at
https://github.com/kubernetes/community/blob/master/contributors/guide/release-notes.md.
-->

```release-note
[dashboard] Fix logout
```

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Enhanced OIDC logout flow: backend logout is now supported, improving
reliability of signing out across services.
* Whitelisted the identity provider domain to enable seamless redirects
during authentication and logout journeys.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-10-13 15:02:47 +02:00
Andrei Kvapil
b474c07c80 Add addtional check to wait for lineage-webhook (#1506)
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>

<!-- Thank you for making a contribution! Here are some tips for you:
- Start the PR title with the [label] of Cozystack component:
- For system components: [platform], [system], [linstor], [cilium],
[kube-ovn], [dashboard], [cluster-api], etc.
- For managed apps: [apps], [tenant], [kubernetes], [postgres],
[virtual-machine] etc.
- For development and maintenance: [tests], [ci], [docs], [maintenance].
- 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


### Release note

<!--  Write a release note:
- Explain what has changed internally and for users.
- Start with the same [label] 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

* **Chores**
* Added a timeout-based step that repeatedly attempts server-side
dry-run creation of a Kubernetes Service (headless) between controller
upgrade and subsequent waits.
* Inserts this validation step without altering existing flow or other
behaviors.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-10-13 15:02:35 +02:00
Andrei Kvapil
5dbdd0eafa [api] Efficient listing of TenantNamespaces (#1507)
## What this PR does

The Cozystack API server lists TenantNamespaces by running a
SubjectAccessReview against every single requested namespace to see if
the user can create a WorkloadMonitor there. Will this is robust in
terms of permissions, delegating the authorization decision to the k8s
API, this is incredibly inefficient and has caused high latency to the
API. This patch simplifies the logic by instead getting the user's
groups and checking if the namespace contains a rolebinding for that
group. That way listing TenantNamespaces is reduced to a list call to
the k8s API for namespaces and another list call for rolebindings across
all namespaces, while authorization is done on the Cozystack API server
instead of making further calls to the k8s API.

### Release note

```release-note
[api] Optimize listing of TenantNamespaces, fixes a bug causing very
high latency to the k8s API.
```

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- Bug Fixes
- TenantNamespace visibility now consistently reflects RBAC role
bindings. Cluster administrators see all namespaces; users only see
namespaces they’re permitted to access.

- Refactor
- Access evaluation simplified to rely on role/rolebinding membership,
removing per-namespace authorization calls and improving listing
performance.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-10-13 15:02:29 +02:00
Andrei Kvapil
21715c02bc The Cozystack Kubernetes tests are now POSIX-compatible (#1509)
This patch replaces bash-specific [[ ... ]] expressions in the
run_kubernetes_test function with POSIX-compliant case and test
constructs. It ensures that the Kubernetes version on each worker node
is verified correctly and that required components (CoreDNS, Cilium,
ingress-nginx, vsnap-crd) are ready before proceeding. Now the tests
work reliably even when executed with /bin/sh, such as in Bats.

```release-note
[tests] Make Kubernetes tests POSIX-compliant and more reliable:
verify worker node versions and ensure required releases (CoreDNS,
Cilium, ingress-nginx, vsnap-crd) are installed and ready.
```

<!-- Thank you for making a contribution! Here are some tips for you:
- Start the PR title with the [label] of Cozystack component:
- For system components: [platform], [system], [linstor], [cilium],
[kube-ovn], [dashboard], [cluster-api], etc.
- For managed apps: [apps], [tenant], [kubernetes], [postgres],
[virtual-machine] etc.
- For development and maintenance: [tests], [ci], [docs], [maintenance].
- 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


### Release note

<!--  Write a release note:
- Explain what has changed internally and for users.
- Start with the same [label] 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

* **Bug Fixes**
* Improved Kubernetes version detection to correctly handle 1.32
variants.
* Made node readiness checks more reliable to reduce false failures
during runs.

* **Refactor**
* Streamlined version matching logic for clearer, more predictable
behavior across releases.

* **Style**
  * Minor formatting cleanups with no functional impact.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-10-13 15:02:18 +02:00
854 changed files with 8187 additions and 77457 deletions

2
.github/CODEOWNERS vendored
View File

@@ -1 +1 @@
* @kvaps @lllamnyp @nbykov0
* @kvaps @lllamnyp @klinch0

View File

@@ -1,188 +0,0 @@
name: Auto Patch Release
on:
schedule:
# Run daily at 2:00 AM CET (1:00 UTC in winter, 0:00 UTC in summer)
# Using 1:00 UTC to approximate 2:00 AM CET
- cron: '0 1 * * *'
workflow_dispatch: # Allow manual trigger
concurrency:
group: auto-release-${{ github.workflow }}
cancel-in-progress: false
jobs:
auto-release:
name: Auto Patch Release
runs-on: [self-hosted]
permissions:
contents: write
pull-requests: read
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
fetch-tags: true
- name: Configure git
env:
GH_PAT: ${{ secrets.GH_PAT }}
run: |
git config user.name "cozystack-bot"
git config user.email "217169706+cozystack-bot@users.noreply.github.com"
git remote set-url origin https://cozystack-bot:${GH_PAT}@github.com/${GITHUB_REPOSITORY}
git config --unset-all http.https://github.com/.extraheader || true
- name: Process release branches
uses: actions/github-script@v7
env:
GH_PAT: ${{ secrets.GH_PAT }}
with:
github-token: ${{ secrets.GH_PAT }}
script: |
const { execSync } = require('child_process');
// Configure git to use PAT for authentication
execSync('git config user.name "cozystack-bot"', { encoding: 'utf8' });
execSync('git config user.email "217169706+cozystack-bot@users.noreply.github.com"', { encoding: 'utf8' });
execSync(`git remote set-url origin https://cozystack-bot:${process.env.GH_PAT}@github.com/${process.env.GITHUB_REPOSITORY}`, { encoding: 'utf8' });
// Remove GITHUB_TOKEN extraheader to ensure PAT is used (needed to trigger other workflows)
execSync('git config --unset-all http.https://github.com/.extraheader || true', { encoding: 'utf8' });
// Get all release-X.Y branches
const branches = execSync('git branch -r | grep -E "origin/release-[0-9]+\\.[0-9]+$" | sed "s|origin/||" | tr -d " "', { encoding: 'utf8' })
.split('\n')
.filter(b => b.trim())
.filter(b => /^release-\d+\.\d+$/.test(b));
console.log(`Found ${branches.length} release branches: ${branches.join(', ')}`);
// Get all published releases (not draft)
const allReleases = await github.rest.repos.listReleases({
owner: context.repo.owner,
repo: context.repo.repo,
per_page: 100
});
// Filter to only published releases (not draft) with tags matching vX.Y.Z (no suffixes)
const publishedReleases = allReleases.data
.filter(r => !r.draft)
.filter(r => /^v\d+\.\d+\.\d+$/.test(r.tag_name));
console.log(`Found ${publishedReleases.length} published releases without suffixes`);
for (const branch of branches) {
console.log(`\n=== Processing branch: ${branch} ===`);
// Extract X.Y from branch name (release-X.Y)
const match = branch.match(/^release-(\d+\.\d+)$/);
if (!match) {
console.log(` ⚠️ Branch ${branch} doesn't match pattern, skipping`);
continue;
}
const [major, minor] = match[1].split('.');
const versionPrefix = `v${major}.${minor}.`;
console.log(` Looking for releases with prefix: ${versionPrefix}`);
// Find the latest published release for this branch (vX.Y.Z without suffixes)
const branchReleases = publishedReleases
.filter(r => r.tag_name.startsWith(versionPrefix))
.filter(r => /^v\d+\.\d+\.\d+$/.test(r.tag_name)); // Ensure no suffixes
if (branchReleases.length === 0) {
console.log(` ⚠️ No published releases found for ${branch}, skipping`);
continue;
}
// Sort by version (descending) to get the latest
branchReleases.sort((a, b) => {
const aVersion = a.tag_name.match(/^v(\d+)\.(\d+)\.(\d+)$/);
const bVersion = b.tag_name.match(/^v(\d+)\.(\d+)\.(\d+)$/);
if (!aVersion || !bVersion) return 0;
const aNum = parseInt(aVersion[1]) * 10000 + parseInt(aVersion[2]) * 100 + parseInt(aVersion[3]);
const bNum = parseInt(bVersion[1]) * 10000 + parseInt(bVersion[2]) * 100 + parseInt(bVersion[3]);
return bNum - aNum;
});
const latestRelease = branchReleases[0];
console.log(` ✅ Latest published release: ${latestRelease.tag_name}`);
// Get the commit SHA for this release tag
let releaseCommitSha;
try {
releaseCommitSha = execSync(`git rev-list -n 1 ${latestRelease.tag_name}`, { encoding: 'utf8' }).trim();
console.log(` Release commit SHA: ${releaseCommitSha}`);
} catch (error) {
console.log(` ⚠️ Could not find commit for tag ${latestRelease.tag_name}, skipping`);
continue;
}
// Checkout the branch
execSync(`git fetch origin ${branch}:${branch}`, { encoding: 'utf8' });
execSync(`git checkout ${branch}`, { encoding: 'utf8' });
// Get the latest commit on the branch
const latestBranchCommit = execSync('git rev-parse HEAD', { encoding: 'utf8' }).trim();
console.log(` Latest branch commit: ${latestBranchCommit}`);
// Check if there are new commits after the release
const commitsAfterRelease = execSync(
`git rev-list ${releaseCommitSha}..HEAD --oneline`,
{ encoding: 'utf8' }
).trim();
if (!commitsAfterRelease) {
console.log(` No new commits after ${latestRelease.tag_name}, skipping`);
continue;
}
console.log(` ✅ Found new commits after release:`);
console.log(commitsAfterRelease);
// Calculate next version (Z+1)
const versionMatch = latestRelease.tag_name.match(/^v(\d+)\.(\d+)\.(\d+)$/);
if (!versionMatch) {
console.log(` ❌ Could not parse version from ${latestRelease.tag_name}, skipping`);
continue;
}
const nextPatch = parseInt(versionMatch[3]) + 1;
const nextTag = `v${versionMatch[1]}.${versionMatch[2]}.${nextPatch}`;
console.log(` 🏷️ Creating new tag: ${nextTag} on commit ${latestBranchCommit}`);
// Create and push the tag with base_ref for workflow triggering
try {
// Delete local tag if exists to force update
try {
execSync(`git tag -d ${nextTag}`, { encoding: 'utf8' });
} catch (e) {
// Tag doesn't exist locally, that's fine
}
// Delete remote tag if exists
try {
execSync(`git push origin :refs/tags/${nextTag}`, { encoding: 'utf8' });
} catch (e) {
// Tag doesn't exist remotely, that's fine
}
// Create tag locally
execSync(`git tag ${nextTag} ${latestBranchCommit}`, { encoding: 'utf8' });
// Push tag with HEAD reference to preserve base_ref
execSync(`git push origin HEAD:refs/tags/${nextTag}`, { encoding: 'utf8' });
console.log(` ✅ Successfully created and pushed tag ${nextTag}`);
} catch (error) {
console.log(` ❌ Error creating/pushing tag ${nextTag}: ${error.message}`);
core.setFailed(`Failed to create tag ${nextTag} for branch ${branch}`);
}
}
console.log(`\n✅ Finished processing all release branches`);

View File

@@ -2,7 +2,7 @@ name: Automatic Backport
on:
pull_request_target:
types: [closed, labeled] # fires when PR is closed (merged) or labeled
types: [closed] # fires when PR is closed (merged)
concurrency:
group: backport-${{ github.workflow }}-${{ github.event.pull_request.number }}
@@ -13,46 +13,22 @@ permissions:
pull-requests: write
jobs:
# Determine which backports are needed
prepare:
backport:
if: |
github.event.pull_request.merged == true &&
(
contains(github.event.pull_request.labels.*.name, 'backport') ||
contains(github.event.pull_request.labels.*.name, 'backport-previous') ||
(github.event.action == 'labeled' && (github.event.label.name == 'backport' || github.event.label.name == 'backport-previous'))
)
contains(github.event.pull_request.labels.*.name, 'backport')
runs-on: [self-hosted]
outputs:
backport_current: ${{ steps.labels.outputs.backport }}
backport_previous: ${{ steps.labels.outputs.backport_previous }}
current_branch: ${{ steps.branches.outputs.current_branch }}
previous_branch: ${{ steps.branches.outputs.previous_branch }}
steps:
- name: Check which labels are present
id: labels
# 1. Decide which maintenance branch should receive the backport
- name: Determine target maintenance branch
id: target
uses: actions/github-script@v7
with:
script: |
const pr = context.payload.pull_request;
const labels = pr.labels.map(l => l.name);
const isBackport = labels.includes('backport');
const isBackportPrevious = labels.includes('backport-previous');
core.setOutput('backport', isBackport ? 'true' : 'false');
core.setOutput('backport_previous', isBackportPrevious ? 'true' : 'false');
console.log(`backport label: ${isBackport}, backport-previous label: ${isBackportPrevious}`);
- name: Determine target branches
id: branches
uses: actions/github-script@v7
with:
script: |
// Get latest release
let latestRelease;
let rel;
try {
latestRelease = await github.rest.repos.getLatestRelease({
rel = await github.rest.repos.getLatestRelease({
owner: context.repo.owner,
repo: context.repo.repo
});
@@ -60,70 +36,18 @@ jobs:
core.setFailed('No existing releases found; cannot determine backport target.');
return;
}
const [maj, min] = latestRelease.data.tag_name.replace(/^v/, '').split('.');
const currentBranch = `release-${maj}.${min}`;
const prevMin = parseInt(min) - 1;
const previousBranch = prevMin >= 0 ? `release-${maj}.${prevMin}` : '';
core.setOutput('current_branch', currentBranch);
core.setOutput('previous_branch', previousBranch);
console.log(`Current branch: ${currentBranch}, Previous branch: ${previousBranch || 'N/A'}`);
// Verify previous branch exists if we need it
if (previousBranch && '${{ steps.labels.outputs.backport_previous }}' === 'true') {
try {
await github.rest.repos.getBranch({
owner: context.repo.owner,
repo: context.repo.repo,
branch: previousBranch
});
console.log(`Previous branch ${previousBranch} exists`);
} catch (e) {
core.setFailed(`Previous branch ${previousBranch} does not exist.`);
return;
}
}
backport:
needs: prepare
if: |
github.event.pull_request.merged == true &&
(needs.prepare.outputs.backport_current == 'true' || needs.prepare.outputs.backport_previous == 'true')
runs-on: [self-hosted]
strategy:
matrix:
backport_type: [current, previous]
steps:
# 1. Determine target branch based on matrix
- name: Set target branch
id: target
if: |
(matrix.backport_type == 'current' && needs.prepare.outputs.backport_current == 'true') ||
(matrix.backport_type == 'previous' && needs.prepare.outputs.backport_previous == 'true')
run: |
if [ "${{ matrix.backport_type }}" == "current" ]; then
echo "branch=${{ needs.prepare.outputs.current_branch }}" >> $GITHUB_OUTPUT
echo "Target branch: ${{ needs.prepare.outputs.current_branch }}"
else
echo "branch=${{ needs.prepare.outputs.previous_branch }}" >> $GITHUB_OUTPUT
echo "Target branch: ${{ needs.prepare.outputs.previous_branch }}"
fi
const [maj, min] = rel.data.tag_name.replace(/^v/, '').split('.');
const branch = `release-${maj}.${min}`;
core.setOutput('branch', branch);
console.log(`Latest release ${rel.data.tag_name}; backporting to ${branch}`);
# 2. Checkout (required by backportaction)
- name: Checkout repository
if: steps.target.outcome == 'success'
uses: actions/checkout@v4
# 3. Create the backport pull request
- name: Create backport PR
id: backport
if: steps.target.outcome == 'success'
uses: korthout/backport-action@v3.2.1
uses: korthout/backport-action@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
label_pattern: '' # don't read labels for targets
target_branches: ${{ steps.target.outputs.branch }}
merge_commits: skip
conflict_resolution: draft_commit_conflicts

View File

@@ -28,7 +28,7 @@ jobs:
- name: Install generate
run: |
curl -sSL https://github.com/cozystack/cozyvalues-gen/releases/download/v1.0.6/cozyvalues-gen-linux-amd64.tar.gz | tar -xzvf- -C /usr/local/bin/ cozyvalues-gen
curl -sSL https://github.com/cozystack/cozyvalues-gen/releases/download/v0.9.0/cozyvalues-gen-linux-amd64.tar.gz | tar -xzvf- -C /usr/local/bin/ cozyvalues-gen
- name: Run pre-commit hooks
run: |

View File

@@ -46,12 +46,7 @@ jobs:
fetch-depth: 0
- name: Create tag on merge commit
env:
GH_PAT: ${{ secrets.GH_PAT }}
run: |
git config user.name "cozystack-bot"
git config user.email "217169706+cozystack-bot@users.noreply.github.com"
git remote set-url origin https://cozystack-bot:${GH_PAT}@github.com/${GITHUB_REPOSITORY}
git tag -f ${{ steps.get_tag.outputs.tag }} ${{ github.sha }}
git push -f origin ${{ steps.get_tag.outputs.tag }}
@@ -110,95 +105,67 @@ jobs:
}
}
# Publish draft release and ensure correct latest flag
- name: Publish draft release
# Get the latest published release
- name: Get the latest published release
id: latest_release
uses: actions/github-script@v7
with:
script: |
const tag = '${{ steps.get_tag.outputs.tag }}';
try {
const rel = await github.rest.repos.getLatestRelease({
owner: context.repo.owner,
repo: context.repo.repo
});
core.setOutput('tag', rel.data.tag_name);
} catch (_) {
core.setOutput('tag', '');
}
# Compare current tag vs latest using semver-utils
- name: Semver compare
id: semver
uses: madhead/semver-utils@v4.3.0
with:
version: ${{ steps.get_tag.outputs.tag }}
compare-to: ${{ steps.latest_release.outputs.tag }}
# Derive flags: prerelease? make_latest?
- name: Calculate publish flags
id: flags
uses: actions/github-script@v7
with:
script: |
const tag = '${{ steps.get_tag.outputs.tag }}'; // v0.31.5-rc.1
const m = tag.match(/^v(\d+\.\d+\.\d+)(-(?:alpha|beta|rc)\.\d+)?$/);
if (!m) {
core.setFailed(`❌ tag '${tag}' must match 'vX.Y.Z' or 'vX.Y.Z-(alpha|beta|rc).N'`);
return;
}
const isRc = Boolean(m[2]);
const version = m[1] + (m[2] ?? ''); // 0.31.5-rc.1
const isRc = Boolean(m[2]);
core.setOutput('is_rc', isRc);
const outdated = '${{ steps.semver.outputs.comparison-result }}' === '<';
core.setOutput('make_latest', isRc || outdated ? 'false' : 'legacy');
// Parse semver string to comparable numbers
function parseSemver(v) {
const match = v.replace(/^v/, '').match(/^(\d+)\.(\d+)\.(\d+)/);
if (!match) return null;
return {
major: parseInt(match[1]),
minor: parseInt(match[2]),
patch: parseInt(match[3])
};
}
// Compare two semver objects
function compareSemver(a, b) {
if (a.major !== b.major) return a.major - b.major;
if (a.minor !== b.minor) return a.minor - b.minor;
return a.patch - b.patch;
}
const currentSemver = parseSemver(tag);
// Get all releases
# Publish draft release with correct flags
- name: Publish draft release
uses: actions/github-script@v7
with:
script: |
const tag = '${{ steps.get_tag.outputs.tag }}';
const releases = await github.rest.repos.listReleases({
owner: context.repo.owner,
repo: context.repo.repo,
per_page: 100
repo: context.repo.repo
});
// Find draft release to publish
const draft = releases.data.find(r => r.tag_name === tag && r.draft);
if (!draft) throw new Error(`Draft release for ${tag} not found`);
// Find max semver among published releases (excluding current draft)
const publishedReleases = releases.data
.filter(r => !r.draft && !r.prerelease)
.filter(r => /^v\d+\.\d+\.\d+$/.test(r.tag_name))
.map(r => ({ id: r.id, tag: r.tag_name, semver: parseSemver(r.tag_name) }))
.filter(r => r.semver !== null);
let maxRelease = null;
for (const rel of publishedReleases) {
if (!maxRelease || compareSemver(rel.semver, maxRelease.semver) > 0) {
maxRelease = rel;
}
}
// Determine if this release should be latest
const isOutdated = maxRelease && compareSemver(currentSemver, maxRelease.semver) < 0;
const makeLatest = (isRc || isOutdated) ? 'false' : 'true';
if (isRc) {
console.log(`🏷️ ${tag} is a prerelease, make_latest: false`);
} else if (isOutdated) {
console.log(`🏷️ ${tag} < ${maxRelease.tag} (max semver), make_latest: false`);
} else {
console.log(`🏷️ ${tag} is the highest version, make_latest: true`);
}
// Publish the release
await github.rest.repos.updateRelease({
owner: context.repo.owner,
repo: context.repo.repo,
release_id: draft.id,
draft: false,
prerelease: isRc,
make_latest: makeLatest
owner: context.repo.owner,
repo: context.repo.repo,
release_id: draft.id,
draft: false,
prerelease: ${{ steps.flags.outputs.is_rc }},
make_latest: '${{ steps.flags.outputs.make_latest }}'
});
console.log(`🚀 Published release ${tag}`);
// If this is a backport/outdated release, ensure the correct release is marked as latest
if (isOutdated && maxRelease) {
console.log(`🔧 Ensuring ${maxRelease.tag} remains the latest release...`);
await github.rest.repos.updateRelease({
owner: context.repo.owner,
repo: context.repo.repo,
release_id: maxRelease.id,
make_latest: 'true'
});
console.log(`✅ Restored ${maxRelease.tag} as latest release`);
}
console.log(`🚀 Published release for ${tag}`);

View File

@@ -1,8 +1,7 @@
name: Pull Request
env:
# TODO: unhardcode this
REGISTRY: iad.ocir.io/idyksih5sir9/cozystack
REGISTRY: ${{ vars.OCIR_REPO }}
on:
pull_request:
types: [opened, synchronize, reopened]
@@ -33,9 +32,6 @@ jobs:
fetch-depth: 0
fetch-tags: true
- name: Run unit tests
run: make unit-tests
- name: Set up Docker config
run: |
if [ -d ~/.docker ]; then
@@ -58,7 +54,7 @@ jobs:
DOCKER_CONFIG: ${{ runner.temp }}/.docker
- name: Build Talos image
run: make -C packages/core/talos talos-nocloud
run: make -C packages/core/installer talos-nocloud
- name: Save git diff as patch
if: "!contains(github.event.pull_request.labels.*.name, 'release')"

View File

@@ -1,78 +0,0 @@
name: Retest
on:
issue_comment:
types: [created]
jobs:
retest:
name: Retest PR
runs-on: ubuntu-latest
if: |
github.event.issue.pull_request &&
contains(github.event.comment.body, '/retest')
permissions:
actions: write
pull-requests: read
steps:
- name: Rerun from Prepare environment
uses: actions/github-script@v7
with:
script: |
const prNumber = context.issue.number;
// Get the PR to find the head SHA
const pr = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber
});
// Find the latest workflow run for this PR
const runs = await github.rest.actions.listWorkflowRuns({
owner: context.repo.owner,
repo: context.repo.repo,
workflow_id: 'pull-requests.yaml',
head_sha: pr.data.head.sha
});
if (runs.data.workflow_runs.length === 0) {
core.setFailed('No workflow runs found for this PR');
return;
}
const latestRun = runs.data.workflow_runs[0];
console.log(`Found workflow run: ${latestRun.id} (${latestRun.status})`);
// Check if workflow is waiting for approval (fork PRs)
if (latestRun.conclusion === 'action_required') {
core.setFailed('Workflow is waiting for approval. A maintainer must approve the workflow first.');
return;
}
// Get jobs for this run
const jobs = await github.rest.actions.listJobsForWorkflowRun({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: latestRun.id
});
// Find "Prepare environment" job
const prepareJob = jobs.data.jobs.find(j => j.name === 'Prepare environment');
if (!prepareJob) {
core.setFailed('Could not find "Prepare environment" job');
return;
}
console.log(`Found job: ${prepareJob.name} (id: ${prepareJob.id}, status: ${prepareJob.status})`);
// Rerun the job
await github.rest.actions.reRunJobForWorkflowRun({
owner: context.repo.owner,
repo: context.repo.repo,
job_id: prepareJob.id
});
console.log(`✅ Triggered rerun of job "${prepareJob.name}" (${prepareJob.id})`);

View File

@@ -123,6 +123,32 @@ jobs:
git commit -m "Prepare release ${GITHUB_REF#refs/tags/}" -s || echo "No changes to commit"
git push origin HEAD || true
# Get `latest_version` from latest published release
- name: Get latest published release
if: steps.check_release.outputs.skip == 'false'
id: latest_release
uses: actions/github-script@v7
with:
script: |
try {
const rel = await github.rest.repos.getLatestRelease({
owner: context.repo.owner,
repo: context.repo.repo
});
core.setOutput('tag', rel.data.tag_name);
} catch (_) {
core.setOutput('tag', '');
}
# Compare tag (A) with latest (B)
- name: Semver compare
if: steps.check_release.outputs.skip == 'false'
id: semver
uses: madhead/semver-utils@v4.3.0
with:
version: ${{ steps.tag.outputs.tag }} # A
compare-to: ${{ steps.latest_release.outputs.tag }} # B
# Create or reuse draft release
- name: Create / reuse draft release
if: steps.check_release.outputs.skip == 'false'

View File

@@ -1,92 +0,0 @@
name: Update Release Notes
on:
push:
branches:
- main
concurrency:
group: update-releasenotes-${{ github.workflow }}
cancel-in-progress: false
jobs:
update-releasenotes:
name: Update Release Notes
runs-on: [self-hosted]
permissions:
contents: write
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Update release notes from changelogs
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const path = require('path');
const changelogDir = 'docs/changelogs';
// Get releases from first page
const releases = await github.rest.repos.listReleases({
owner: context.repo.owner,
repo: context.repo.repo,
per_page: 30
});
console.log(`Found ${releases.data.length} releases (first page only)`);
// Process each release
for (const release of releases.data) {
const tag = release.tag_name;
const changelogFile = `${tag}.md`;
const changelogPath = path.join(changelogDir, changelogFile);
console.log(`\nProcessing release: ${tag}`);
// Check if changelog file exists
if (!fs.existsSync(changelogPath)) {
console.log(` ⚠️ Changelog file ${changelogFile} does not exist, skipping...`);
continue;
}
// Read changelog file content
let changelogContent;
try {
changelogContent = fs.readFileSync(changelogPath, 'utf8');
} catch (error) {
console.log(` ❌ Error reading file ${changelogPath}: ${error.message}`);
continue;
}
if (!changelogContent.trim()) {
console.log(` ⚠️ Changelog file ${changelogFile} is empty, skipping...`);
continue;
}
// Check if content is already up to date
const currentBody = release.body || '';
if (currentBody.trim() === changelogContent.trim()) {
console.log(` ✓ Content is already up to date, skipping...`);
continue;
}
// Update release notes
try {
await github.rest.repos.updateRelease({
owner: context.repo.owner,
repo: context.repo.repo,
release_id: release.id,
body: changelogContent
});
console.log(` ✅ Successfully updated release notes for ${tag}`);
} catch (error) {
console.log(` ❌ Error updating release ${tag}: ${error.message}`);
core.setFailed(`Failed to update release notes for ${tag}`);
}
}

1
.gitignore vendored
View File

@@ -1,5 +1,4 @@
_out
_repos
.git
.idea
.vscode

View File

@@ -31,5 +31,4 @@ This list is sorted in chronological order, based on the submission date.
| [gohost](https://gohost.kz/) | @karabass_off | 2024-02-01 | Our company has been working in the market of Kazakhstan for more than 15 years, providing clients with a standard set of services: VPS/VDC, IaaS, shared hosting, etc. Now we are expanding the lineup by introducing Bare Metal Kubenetes cluster under Cozystack management. |
| [Urmanac](https://urmanac.com) | @kingdonb | 2024-12-04 | Urmanac is the future home of a hosting platform for the knowledge base of a community of personal server enthusiasts. We use Cozystack to provide support services for web sites hosted using both conventional deployments and on SpinKube, with WASM. |
| [Hidora](https://hikube.cloud) | @matthieu-robin | 2025-09-17 | Hidora is a Swiss cloud provider delivering managed services and infrastructure solutions through datacenters located in Switzerland, ensuring data sovereignty and reliability. Its sovereign cloud platform, Hikube, is designed to run workloads with high availability across multiple datacenters, providing enterprises with a secure and scalable foundation for their applications based on Cozystack. |
| [QOSI](https://qosi.kz) | @tabu-a | 2025-10-04 | QOSI is a non-profit organization driving open-source adoption and digital sovereignty across Kazakhstan and Central Asia. We use Cozystack as a platform for deploying sovereign, GPU-enabled clouds and educational environments under the National AI Program. Our goal is to accelerate the regions transition toward open, self-hosted cloud-native technologies |
| [Cloupard](https://cloupard.kz/) | @serjiott | 2025-12-18 | Cloupard is a public cloud provider offering IaaS and PaaS services via datacenters in Kazakhstan and Uzbekistan. Uses CozyStack on bare metal to extend its managed PaaS offerings. |
|

View File

@@ -1,62 +0,0 @@
# AI Agents Overview
This file provides structured guidance for AI coding assistants and agents
working with the **Cozystack** project.
## Activation
**CRITICAL**: When the user asks you to do something that matches the scope of a documented process, you MUST read the corresponding documentation file and follow the instructions exactly as written.
- **Commits, PRs, git operations** (e.g., "create a commit", "make a PR", "fix review comments", "rebase", "cherry-pick")
- Read: [`contributing.md`](./docs/agents/contributing.md)
- Action: Read the entire file and follow ALL instructions step-by-step
- **Changelog generation** (e.g., "generate changelog", "create changelog", "prepare changelog for version X")
- Read: [`changelog.md`](./docs/agents/changelog.md)
- Action: Read the entire file and follow ALL steps in the checklist. Do NOT skip any mandatory steps
- **Release creation** (e.g., "create release", "prepare release", "tag release", "make a release")
- Read: [`releasing.md`](./docs/agents/releasing.md)
- Action: Read the file and follow the referenced release process in `docs/release.md`
- **Project structure, conventions, code layout** (e.g., "where should I put X", "what's the convention for Y", "how is the project organized")
- Read: [`overview.md`](./docs/agents/overview.md)
- Action: Read relevant sections to understand project structure and conventions
- **General questions about contributing**
- Read: [`contributing.md`](./docs/agents/contributing.md)
- Action: Read the file to understand git workflow, commit format, PR process
**Important rules:**
-**ONLY read the file if the task matches the documented process scope** - do not read files for tasks that don't match their purpose
-**ALWAYS read the file FIRST** before starting the task (when applicable)
-**Follow instructions EXACTLY** as written in the documentation
-**Do NOT skip mandatory steps** (especially in changelog.md)
-**Do NOT assume** you know the process - always check the documentation when the task matches
-**Do NOT read files** for tasks that are outside their documented scope
- 📖 **Note**: [`overview.md`](./docs/agents/overview.md) can be useful as a reference to understand project structure and conventions, even when not explicitly required by the task
## Project Overview
**Cozystack** is a Kubernetes-based platform for building cloud infrastructure with managed services (databases, VMs, K8s clusters), multi-tenancy, and GitOps delivery.
## Quick Reference
### Code Structure
- `packages/core/` - Core platform charts (installer, platform)
- `packages/system/` - System components (CSI, CNI, operators)
- `packages/apps/` - User-facing applications in catalog
- `packages/extra/` - Tenant-specific modules
- `cmd/`, `internal/`, `pkg/` - Go code
- `api/` - Kubernetes CRDs
### Conventions
- **Helm Charts**: Umbrella pattern, vendored upstream charts in `charts/`
- **Go Code**: Controller-runtime patterns, kubebuilder style
- **Git Commits**: `[component] Description` format with `--signoff`
### What NOT to Do
- ❌ Edit `/vendor/`, `zz_generated.*.go`, upstream charts directly
- ❌ Modify `go.mod`/`go.sum` manually (use `go get`)
- ❌ Force push to main/master
- ❌ Commit built artifacts from `_out`

View File

@@ -1,4 +1,4 @@
.PHONY: manifests repos assets unit-tests helm-unit-tests
.PHONY: manifests repos assets
build-deps:
@command -V find docker skopeo jq gh helm > /dev/null
@@ -17,7 +17,7 @@ build: build-deps
make -C packages/system/cozystack-controller image
make -C packages/system/lineage-controller-webhook image
make -C packages/system/cilium image
make -C packages/system/linstor image
make -C packages/system/kubeovn image
make -C packages/system/kubeovn-webhook image
make -C packages/system/kubeovn-plunger image
make -C packages/system/dashboard image
@@ -26,8 +26,6 @@ build: build-deps
make -C packages/system/bucket image
make -C packages/system/objectstorage-controller image
make -C packages/core/testing image
make -C packages/core/talos image
make -C packages/core/platform image
make -C packages/core/installer image
make manifests
@@ -42,17 +40,12 @@ manifests:
(cd packages/core/installer/; helm template -n cozy-installer installer .) > _out/assets/cozystack-installer.yaml
assets:
make -C packages/core/talos assets
make -C packages/core/installer assets
test:
make -C packages/core/testing apply
make -C packages/core/testing test
unit-tests: helm-unit-tests
helm-unit-tests:
hack/helm-unit-tests.sh
prepare-env:
make -C packages/core/testing apply
make -C packages/core/testing prepare-cluster

View File

@@ -200,6 +200,22 @@ func main() {
os.Exit(1)
}
if err = (&controller.TenantHelmReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "TenantHelmReconciler")
os.Exit(1)
}
if err = (&controller.CozystackConfigReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "CozystackConfigReconciler")
os.Exit(1)
}
cozyAPIKind := "DaemonSet"
if reconcileDeployment {
cozyAPIKind = "Deployment"
@@ -213,14 +229,6 @@ func main() {
os.Exit(1)
}
if err = (&controller.CozystackResourceDefinitionHelmReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "CozystackResourceDefinitionHelmReconciler")
os.Exit(1)
}
dashboardManager := &dashboard.Manager{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),

View File

@@ -1,666 +0,0 @@
# Changelog Generation Instructions
This file contains detailed instructions for AI-powered IDE on how to generate changelogs for Cozystack releases.
## When to use these instructions
Follow these instructions when the user explicitly asks to generate a changelog.
## Required Tools
Before generating changelogs, ensure you have access to `gh` (GitHub CLI) tool, which is used to fetch commit and PR author information. The GitHub CLI is used to correctly identify PR authors from commits and pull requests.
## Changelog Generation Process
When the user asks to generate a changelog, follow these steps in the specified order:
**CHECKLIST - All actions that must be completed:**
- [ ] Step 1: Update information from remote (git fetch)
- [ ] Step 2: Check current branch (must be main)
- [ ] Step 3: Determine release type and previous version (minor vs patch release)
- [ ] Step 4: Determine versions and analyze existing changelogs
- [ ] Step 5: Get the list of commits for the release period
- [ ] Step 6: Check additional repositories (website is REQUIRED, optional repos if tags exist)
- [ ] **MANDATORY**: Check website repository for documentation changes WITH authors and PR links via GitHub CLI
- [ ] **MANDATORY**: Check ALL optional repositories (talm, boot-to-talos, cozyhr, cozy-proxy) for tags during release period
- [ ] **MANDATORY**: For ALL commits from additional repos, get GitHub username via CLI, prioritizing PR author over commit author.
- [ ] Step 7: Analyze commits (extract PR numbers, authors, user impact)
- [ ] **MANDATORY**: For EVERY PR in main repo, get PR author via `gh pr view <PR_NUMBER> --json author --jq .author.login` (do NOT skip this step)
- [ ] **MANDATORY**: Extract PR numbers from commit messages, then use `gh pr view` for each PR to get the PR author. Do NOT use commit author. Only for commits without PR numbers (rare), fall back to `gh api repos/cozystack/cozystack/commits/<hash> --jq '.author.login'`
- [ ] Step 8: Form new changelog (structure, format, generate contributors list)
- [ ] Step 9: Verify completeness and save
### 1. Updating information from remote
```bash
git fetch --tags --force --prune
```
This is necessary to get up-to-date information about tags and commits from the remote repository.
### 2. Checking current branch
Make sure we are on the `main` branch:
```bash
git branch --show-current
```
### 3. Determining release type and previous version
**Important**: Determine if you're generating a changelog for a **minor release** (vX.Y.0) or a **patch release** (vX.Y.Z where Z > 0).
**For minor releases (vX.Y.0):**
- Each minor version lives and evolves in its own branch (`release-X.Y`)
- You MUST compare with the **previous minor version** (v(X-1).Y.0), not the last patch release
- This ensures you capture all changes from the entire minor version cycle, including all patch releases
- Example: For v0.38.0, compare with v0.37.0 (not v0.37.8)
- Run a separate cycle to check the diff with the zero version of the previous minor release
**For patch releases (vX.Y.Z where Z > 0):**
- Compare with the previous patch version (vX.Y.(Z-1))
- Example: For v0.37.2, compare with v0.37.1
### 4. Determining versions and analyzing existing changelogs
**Determine the last published version:**
1. Get the list of version tags:
```bash
git tag -l 'v[0-9]*.[0-9]*.[0-9]*' | sort -V
```
2. Get the last tag:
```bash
git tag -l 'v[0-9]*.[0-9]*.[0-9]*' | sort -V | tail -1
```
3. Compare tags with existing changelog files in `docs/changelogs/` to determine the last published version (the newest file `vX.Y.Z.md`)
**Study existing changelog format:**
- Review recent changelog files to understand the format and structure
- Pay attention to:
- **Feature Highlights format** (for minor releases): Use `## Feature Highlights` with `### Feature Name` subsections containing detailed descriptions (2-4 paragraphs each). See v0.35.0 and v0.36.0 for examples.
- Section structure (Major Features and Improvements, Security, Fixes, Dependencies, etc.)
- PR link format (e.g., `[**@username**](https://github.com/username) in #1234`)
- Change description style
- Presence of Breaking changes sections, etc.
### 5. Getting the list of commits
**Important**: Determine if you're generating a changelog for a **minor release** (vX.Y.0) or a **patch release** (vX.Y.Z where Z > 0).
**For patch releases (vX.Y.Z where Z > 0):**
Get the list of commits starting from the previous patch version to HEAD:
**⚠️ CRITICAL: Do NOT use --first-parent flag! It will skip merge commits including backports!**
```bash
# Get all commits including merge commits (backports)
git log <previous_version>..HEAD --pretty=format:"%h - %s (%an, %ar)"
```
For example, if generating changelog for `v0.37.2`:
```bash
git log v0.37.1..HEAD --pretty=format:"%h - %s (%an, %ar)"
```
**⚠️ IMPORTANT: Check for backports:**
- Look for commits with "[Backport release-X.Y]" in the commit message
- For backport PRs, find the original PR number mentioned in the backport commit message or PR description
- Use the original PR author (not the backport PR author) when creating changelog entries
- Include both the original PR number and backport PR number in the changelog entry (e.g., `#1606, #1609`)
**For minor releases (vX.Y.0):**
Minor releases must include **all changes** from patch releases of the previous minor version. Get commits from the previous minor release:
**⚠️ CRITICAL: Do NOT use --first-parent flag! It will skip merge commits including backports!**
```bash
# For v0.38.0, get all commits since v0.37.0 (including all patch releases v0.37.1, v0.37.2, etc.)
git log v<previous_minor_version>..HEAD --pretty=format:"%h - %s (%an, %ar)"
```
For example, if generating changelog for `v0.38.0`:
```bash
git log v0.37.0..HEAD --pretty=format:"%h - %s (%an, %ar)"
```
This will include all commits from v0.37.1, v0.37.2, v0.37.3, etc., up to v0.38.0.
**⚠️ IMPORTANT: Always check merge commits:**
- Merge commits may contain backports that need to be included
- Check all commits in the range, including merge commits
- For backports, always find and reference the original PR
### 6. Analyzing additional repositories
**⚠️ CRITICAL: This step is MANDATORY and must NOT be skipped!**
Cozystack release may include changes from related repositories. Check and include commits from these repositories if tags were released during the release period:
**Required repositories:**
- **Documentation**: [https://github.com/cozystack/website](https://github.com/cozystack/website)
- **MANDATORY**: Always check this repository for documentation changes during the release period
- **MANDATORY**: Get GitHub username for EVERY commit. Extract PR number from commit message, then use `gh pr view <PR_NUMBER> --repo cozystack/website --json author --jq .author.login` to get PR author. Only if no PR number, fall back to `gh api repos/cozystack/website/commits/<hash> --jq '.author.login'`
**Optional repositories (MUST check ALL of them for tags during release period):**
- [https://github.com/cozystack/talm](https://github.com/cozystack/talm)
- [https://github.com/cozystack/boot-to-talos](https://github.com/cozystack/boot-to-talos)
- [https://github.com/cozystack/cozyhr](https://github.com/cozystack/cozyhr)
- [https://github.com/cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy)
**⚠️ IMPORTANT**: You MUST check ALL optional repositories for tags created during the release period. Do NOT skip this step even if you think there might not be any tags. Use the process below to verify.
**Process for each repository:**
1. **Get release period dates:**
```bash
# Get dates for the release period
cd /path/to/cozystack
RELEASE_START=$(git log -1 --format=%ai v<previous_version>)
RELEASE_END=$(git log -1 --format=%ai HEAD)
```
2. **Check for commits in website repository (always required):**
```bash
# Ensure website repository is cloned and up-to-date
mkdir -p _repos
if [ ! -d "_repos/website" ]; then
cd _repos && git clone https://github.com/cozystack/website.git && cd ..
fi
cd _repos/website
git fetch --all --tags --force
git checkout main 2>/dev/null || git checkout master
git pull
# Get commits between release dates (with some buffer)
git log --since="$RELEASE_START" --until="$RELEASE_END" --format="%H|%s|%an" | while IFS='|' read -r commit_hash subject author_name; do
# Extract PR number from commit message
PR_NUMBER=$(git log -1 --format="%B" "$commit_hash" | grep -oE '#[0-9]+' | head -1 | tr -d '#')
# ALWAYS use PR author if PR number found, not commit author
if [ -n "$PR_NUMBER" ]; then
GITHUB_USERNAME=$(gh pr view "$PR_NUMBER" --repo cozystack/website --json author --jq '.author.login // empty' 2>/dev/null)
echo "$commit_hash|$subject|$author_name|$GITHUB_USERNAME|cozystack/website#$PR_NUMBER"
else
# Only fallback to commit author if no PR number found (rare)
GITHUB_USERNAME=$(gh api repos/cozystack/website/commits/$commit_hash --jq '.author.login // empty')
echo "$commit_hash|$subject|$author_name|$GITHUB_USERNAME|cozystack/website@${commit_hash:0:7}"
fi
done
# Look for documentation updates, new pages, or significant content changes
# Include these in the "Documentation" section of the changelog WITH authors and PR links
```
3. **For optional repositories, check if tags exist during release period:**
**⚠️ MANDATORY: You MUST check ALL optional repositories (talm, boot-to-talos, cozyhr, cozy-proxy). Do NOT skip any repository!**
**Use the helper script:**
```bash
# Get release period dates
RELEASE_START=$(git log -1 --format=%ai v<previous_version>)
RELEASE_END=$(git log -1 --format=%ai HEAD)
# Run the script to check all optional repositories
./docs/changelogs/hack/check-optional-repos.sh "$RELEASE_START" "$RELEASE_END"
```
The script will:
- Check ALL optional repositories (talm, boot-to-talos, cozyhr, cozy-proxy)
- Look for tags created during the release period
- Get commits between tags (if tags exist) or by date range (if no tags)
- Extract PR numbers from commit messages
- For EVERY commit with PR number, get PR author via CLI: `gh pr view <PR_NUMBER> --repo cozystack/<repo> --json author --jq .author.login` (ALWAYS use PR author, not commit author)
- For commits without PR numbers (rare), fallback to: `gh api repos/cozystack/<repo>/commits/<hash> --jq '.author.login'`
- Output results in format: `commit_hash|subject|author_name|github_username|cozystack/repo#PR_NUMBER` or `cozystack/repo@commit_hash`
4. **Extract PR numbers and authors using GitHub CLI:**
- **ALWAYS use PR author, not commit author** for commits from additional repositories
- For each commit, extract PR number from commit message first: Extract `#123` pattern from commit message
- If PR number found, use `gh pr view <PR_NUMBER> --repo cozystack/<repo> --json author --jq .author.login` to get PR author (the person who wrote the code)
- Only if no PR number found (rare), fallback to commit author: `gh api repos/cozystack/<repo>/commits/<hash> --jq '.author.login'`
- **Prefer PR numbers**: Use format `cozystack/website#123` if PR number found in commit message
- **Fallback to commit hash**: Use format `cozystack/website@abc1234` if no PR number
- **ALWAYS include author**: Every entry from additional repositories MUST include author in format `([**@username**](https://github.com/username) in cozystack/repo#123)`
- Determine user impact and categorize appropriately
- Format entries with repository prefix: `[website]`, `[talm]`, etc.
**Example entry format for additional repositories:**
```markdown
# If PR number found in commit message (REQUIRED format):
* **[website] Update installation documentation**: Improved installation guide with new examples ([**@username**](https://github.com/username) in cozystack/website#123).
# If no PR number (fallback, use commit hash):
* **[website] Update installation documentation**: Improved installation guide with new examples ([**@username**](https://github.com/username) in cozystack/website@abc1234).
# For optional repositories:
* **[talm] Add new feature**: Description of the change ([**@username**](https://github.com/username) in cozystack/talm#456).
```
**CRITICAL**:
- **ALWAYS include author** for every entry from additional repositories
- **ALWAYS include PR link or commit hash** for every entry
- Never add entries without author and PR/commit reference
- **ALWAYS use PR author, not commit author**: Extract PR number from commit message, then use `gh pr view <PR_NUMBER> --repo cozystack/<repo> --json author --jq .author.login` to get the PR author (the person who wrote the code)
- Only if no PR number found (rare), fallback to commit author: `gh api repos/cozystack/<repo>/commits/<hash> --jq '.author.login'`
- The commit author (especially for squash/merge commits) is usually the person who merged the PR, not the person who wrote the code
### 7. Analyzing commits and PRs
**⚠️ CRITICAL: You MUST get the author from PR, not from commit! Always use `gh pr view` to get the PR author. Do NOT use commit author!**
**Get all PR numbers from commits:**
**⚠️ CRITICAL: Do NOT use --no-merges flag! It will skip merge commits including backports!**
```bash
# Extract all PR numbers from commit messages in the release range (including merge commits)
git log <previous_version>..<new_version> --format="%s%n%b" | grep -oE '#[0-9]+' | sort -u | tr -d '#'
```
**⚠️ IMPORTANT: Handle backports correctly:**
- Backport PRs have format: `[Backport release-X.Y] <original title> (#BACKPORT_PR_NUMBER)`
- The backport commit message or PR description usually mentions the original PR number
- For backport entries in changelog, use the original PR author (not the backport PR author)
- Include both original and backport PR numbers in the changelog entry (e.g., `#1606, #1609`)
- To find original PR from backport: Check the backport PR description or commit message for "Backport of #ORIGINAL_PR"
**For each PR number, get the author:**
**CRITICAL**: The commit author (especially for squash/merge commits) is usually the person who merged the PR (or GitHub bot), NOT the person who wrote the code. **ALWAYS use the PR author**, not the commit author.
**⚠️ MANDATORY: ALWAYS use `gh pr view` to get the PR author. Do NOT use commit author!**
**ALWAYS use GitHub CLI** to get the PR author:
```bash
# Usage: Get PR author - MANDATORY for EVERY PR
# Loop through ALL PR numbers and get PR author (including backports)
git log <previous_version>..<new_version> --format="%s%n%b" | grep -oE '#[0-9]+' | sort -u | tr -d '#' | while read PR_NUMBER; do
# Check if this is a backport PR
BACKPORT_INFO=$(gh pr view "$PR_NUMBER" --json body --jq '.body' 2>/dev/null | grep -i "backport of #" || echo "")
if [ -n "$BACKPORT_INFO" ]; then
# Extract original PR number from backport description
ORIGINAL_PR=$(echo "$BACKPORT_INFO" | grep -oE 'backport of #([0-9]+)' | grep -oE '[0-9]+' | head -1)
if [ -n "$ORIGINAL_PR" ]; then
# Use original PR author
GITHUB_USERNAME=$(gh pr view "$ORIGINAL_PR" --json author --jq '.author.login // empty')
PR_TITLE=$(gh pr view "$ORIGINAL_PR" --json title --jq '.title // empty')
echo "$PR_NUMBER|$ORIGINAL_PR|$GITHUB_USERNAME|$PR_TITLE|BACKPORT"
else
# Fallback to backport PR author if original not found
GITHUB_USERNAME=$(gh pr view "$PR_NUMBER" --json author --jq '.author.login // empty')
PR_TITLE=$(gh pr view "$PR_NUMBER" --json title --jq '.title // empty')
echo "$PR_NUMBER||$GITHUB_USERNAME|$PR_TITLE|BACKPORT"
fi
else
# Regular PR
GITHUB_USERNAME=$(gh pr view "$PR_NUMBER" --json author --jq '.author.login // empty')
PR_TITLE=$(gh pr view "$PR_NUMBER" --json title --jq '.title // empty')
echo "$PR_NUMBER||$GITHUB_USERNAME|$PR_TITLE|REGULAR"
fi
done
```
**⚠️ IMPORTANT**: You must run this for EVERY PR in the release period. Do NOT skip any PRs or assume the GitHub username based on the git author name.
**CRITICAL**: Always use `gh pr view <PR_NUMBER> --json author --jq .author.login` to get the PR author. This correctly identifies the person who wrote the code, not the person who merged it (which is especially important for squash merges).
**Why this matters**: Using the wrong author in changelogs gives incorrect credit and can confuse contributors. The merge/squash commit is created by the person who clicks "Merge" in GitHub, not the PR author.
**For commits without PR numbers (rare):**
- Only if a commit has no PR number, fall back to commit author: `gh api repos/cozystack/cozystack/commits/<hash> --jq '.author.login'`
- But this should be very rare - most commits should have PR numbers
**Extract PR number from commit messages:**
- Check commit message subject (`%s`) and body (`%b`) for PR references: `#1234` or `(#1234)`
- **Primary method**: Extract from commit message format `(#PR_NUMBER)` or `in #PR_NUMBER` or `Merge pull request #1234`
- Use regex: `grep -oE '#[0-9]+'` to find all PR numbers
**⚠️ CRITICAL: Verify PR numbers match commit messages!**
- Always verify that the PR number in the changelog matches the PR number in the commit message
- Common mistake: Using wrong PR number (e.g., #1614 instead of #1617) when multiple similar commits exist
- To verify: Check the actual commit message: `git log <commit_hash> -1 --format="%s%n%b" | grep -oE '#[0-9]+'`
- If multiple PR numbers appear in a commit, use the one that matches the PR title/description
- For merge commits, check the merged branch commits, not just the merge commit message
3. **Understand the change:**
```bash
# Get PR details (preferred method)
gh pr view <PR_NUMBER> --json title,body,url
# Or get commit details if no PR number
git show <commit_hash> --stat
git show <commit_hash>
```
- Review PR description and changed files
- Understand functionality added/changed/fixed
- **Determine user impact**: What can users do now? What problems are fixed? What improvements do users experience?
4. **For release branches (backports):**
- If commit is from `release-X.Y` branch, check if it's a backport
- Find original commit in `main` to get correct PR number:
```bash
git log origin/main --grep="<part of commit message>" --oneline
```
### 8. Forming a new changelog
Create a new changelog file in the format matching previous versions:
1. **Determine the release type:**
- **Minor release (vX.Y.0)** - use full format with **Feature Highlights** section. **Must include all changes from patch releases of the previous minor version** (e.g., v0.38.0 should include changes from v0.37.1, v0.37.2, v0.37.3, etc.)
- **Patch release (vX.Y.Z, where Z > 0)** - use more compact format, includes only changes since the previous patch release
**Feature Highlights format for minor releases:**
- Use section header: `## Feature Highlights`
- Include 3-6 major features as subsections with `### Feature Name` headers
- Each feature subsection should contain:
- **Detailed description** (2-4 paragraphs) explaining:
- What the feature is and what problem it solves
- How it works and what users can do with it
- How to use it (if applicable)
- Benefits and impact for users
- **Links to documentation** when available (use markdown links)
- **Code examples or configuration snippets** if helpful
- Focus on user value and practical implications, not just technical details
- Each feature should be substantial enough to warrant its own subsection
- Order features by importance/impact (most important first)
- Example format:
```markdown
## Feature Highlights
### Feature Name
Detailed description paragraph explaining what the feature is...
Another paragraph explaining how it works and what users can do...
Learn more in the [documentation](https://cozystack.io/docs/...).
```
**Important for minor releases**: After collecting all commits, **systematically verify** that all PRs from patch releases are included:
```bash
# Extract all PR numbers from patch release changelogs
grep -h "#[0-9]\+" docs/changelogs/v<previous_minor>.*.md | sort -u
# Extract all PR numbers from the new minor release changelog
grep -h "#[0-9]\+" docs/changelogs/v<new_minor>.0.md | sort -u
# Compare and identify missing PRs
# Ensure every PR from patch releases appears in the minor release changelog
```
2. **Structure changes by categories:**
**For minor releases (vX.Y.0):**
- **Feature Highlights** (required) - see format above
- **Major Features and Improvements** - detailed list of all major features and improvements
- **Improvements (minor)** - smaller improvements and enhancements
- **Bug fixes** - all bug fixes
- **Security** - security-related changes
- **Dependencies & version updates** - dependency updates
- **System Configuration** - system-level configuration changes
- **Development, Testing, and CI/CD** - development and testing improvements
- **Documentation** (include changes from website repository here - **MUST include authors and PR links for all entries**)
- **Breaking changes & upgrade notes** (if any)
- **Refactors & chores** (if any)
**For patch releases (vX.Y.Z where Z > 0):**
- **Features and Improvements** - new features and improvements
- **Fixes** - bug fixes
- **Security** - security-related changes
- **Dependencies** - dependency updates
- **System Configuration** - system-level configuration changes
- **Development, Testing, and CI/CD** - development and testing improvements
- **Documentation** (include changes from website repository here - **MUST include authors and PR links for all entries**)
- **Migration and Upgrades** (if applicable)
**Note**: When including changes from additional repositories, group them logically with main repository changes, or create separate subsections if there are many changes from a specific repository.
3. **Entry format:**
- Use the format: `* **Brief description**: detailed description ([**@username**](https://github.com/username) in #PR_NUMBER)`
- **CRITICAL - Get authorship correctly**:
- **ALWAYS use PR author, not commit author**: Extract PR number from commit message, then use `gh pr view` to get the PR author. The commit author (especially for squash/merge commits) is usually the person who merged the PR (or GitHub bot), NOT the person who wrote the code.
```bash
# Get PR author from GitHub CLI (correct method)
# Step 1: Extract PR number from commit message
PR_NUMBER=$(git log <commit_hash> -1 --format="%s%n%b" | grep -oE '#[0-9]+' | head -1 | tr -d '#')
# Step 2: Get PR author (the person who wrote the code)
if [ -n "$PR_NUMBER" ]; then
GITHUB_USERNAME=$(gh pr view "$PR_NUMBER" --json author --jq '.author.login')
else
# Only fallback to commit author if no PR number found (rare)
GITHUB_USERNAME=$(gh api repos/cozystack/cozystack/commits/<commit_hash> --jq '.author.login')
fi
```
**Example**: For PR #1507, the squash commit has author "kvaps" (who merged), but the PR author is "lllamnyp" (who wrote the code). Using `gh pr view 1507 --json author --jq .author.login` correctly returns "lllamnyp".
- **For regular commits**: Use the commit author directly:
```bash
git log <commit_hash> -1 --format="%an|%ae"
```
- **Validation**: Before adding to changelog, verify the author by checking:
- For merge commits: Compare merge commit author vs PR author (they should be different)
- Check existing changelogs for author name to GitHub username mappings
- Verify with: `git log <merge_commit>^1..<merge_commit>^2 --format="%an" --no-merges`
- **Map author name to GitHub username**: Check existing changelogs for author name mappings, or extract from PR links in commit messages
- **Always include user impact**: Each entry must explain how the change affects users
- For new features: explain what users can now do
- For bug fixes: explain what problem is solved for users
- For improvements: explain what users will experience better
- For breaking changes: clearly state what users need to do
- Group related changes
- Use bold font for important components/modules
- Focus on user value, not just technical details
4. **Add a link to the full changelog:**
**For patch releases (vX.Y.Z where Z > 0):**
```markdown
**Full Changelog**: https://github.com/cozystack/cozystack/compare/v<previous_patch_version>...v<new_version>
```
Example: For v0.37.2, use `v0.37.1...v0.37.2`
**For minor releases (vX.Y.0):**
```markdown
**Full Changelog**: https://github.com/cozystack/cozystack/compare/v<previous_minor_version>...v<new_version>
```
Example: For v0.38.0, use `v0.37.0...v0.38.0` (NOT `v0.37.8...v0.38.0`)
**Important**: Minor releases must reference the previous minor release (vX.Y.0), not the last patch release, to include all changes from the entire minor version cycle.
5. **Generate contributors list:**
**⚠️ SIMPLIFIED APPROACH: Extract contributors from the generated changelog itself!**
Since you've already generated the changelog with all PR authors correctly identified, simply extract GitHub usernames from the changelog entries:
```bash
# Extract all GitHub usernames from the current release changelog
# This method is simpler and more reliable than extracting from git history
# For patch releases: extract from the current changelog file
grep -oE '\[@[a-zA-Z0-9_-]+\]' docs/changelogs/v<version>.md | \
sed 's/\[@/@/' | sed 's/\]//' | \
sort -u
# For minor releases: extract from the current changelog file
grep -oE '\[@[a-zA-Z0-9_-]+\]' docs/changelogs/v<version>.md | \
sed 's/\[@/@/' | sed 's/\]//' | \
sort -u
```
**Get all previous contributors (to identify new ones):**
```bash
# Extract GitHub usernames from all previous changelogs
grep -hE '\[@[a-zA-Z0-9_-]+\]' docs/changelogs/v*.md | \
grep -oE '@[a-zA-Z0-9_-]+' | \
sort -u > /tmp/previous_contributors.txt
```
**Identify new contributors (first-time contributors):**
```bash
# Get current release contributors from the changelog
grep -oE '@[a-zA-Z0-9_-]+' docs/changelogs/v<version>.md | \
sort -u > /tmp/current_contributors.txt
# Get all previous contributors
grep -hE '@[a-zA-Z0-9_-]+' docs/changelogs/v*.md | \
grep -oE '@[a-zA-Z0-9_-]+' | \
sort -u > /tmp/all_previous_contributors.txt
# Find new contributors (those in current but not in previous)
comm -23 <(sort /tmp/current_contributors.txt) <(sort /tmp/all_previous_contributors.txt)
```
**Why this approach is better:**
- ✅ Uses the already-verified PR authors from the changelog (no need to query GitHub API again)
- ✅ Automatically handles backports correctly (original PR authors are already in the changelog)
- ✅ Simpler and faster (no git log parsing or API calls)
- ✅ More reliable (matches exactly what's in the changelog)
- ✅ Works for both patch and minor releases
**Add contributors section to changelog:**
Place the contributors section at the end of the changelog, before the "Full Changelog" link:
```markdown
## Contributors
We'd like to thank all contributors who made this release possible:
* [**@username1**](https://github.com/username1)
* [**@username2**](https://github.com/username2)
* [**@username3**](https://github.com/username3)
* ...
### New Contributors
We're excited to welcome our first-time contributors:
* [**@newuser1**](https://github.com/newuser1) - First contribution!
* [**@newuser2**](https://github.com/newuser2) - First contribution!
```
**Formatting guidelines:**
- List contributors in alphabetical order by GitHub username
- Use the format: `* [**@username**](https://github.com/username)`
- For new contributors, add " - First contribution!" note
- If GitHub username cannot be determined, you can skip that contributor or use their git author name
**When to include:**
- **For patch releases**: Contributors section is optional, but can be included for significant releases
- **For minor releases (vX.Y.0)**: Contributors section is required - you must generate and include the contributors list
- Always verify GitHub usernames by checking commit messages, PR links in changelog entries, or by examining PR details
6. **Add a comment with a link to the GitHub release:**
```markdown
<!--
https://github.com/cozystack/cozystack/releases/tag/v<new_version>
-->
```
### 9. Verification and saving
**Before saving, verify completeness:**
**For ALL releases:**
- [ ] Step 5 completed: **ALL commits included** (including merge commits and backports) - do not skip any commits
- [ ] Step 5 completed: **Backports identified and handled correctly** - original PR author used, both original and backport PR numbers included
- [ ] Step 6 completed: Website repository checked for documentation changes WITH authors and PR links via GitHub CLI
- [ ] Step 6 completed: **ALL** optional repositories (talm, boot-to-talos, cozyhr, cozy-proxy) checked for tags during release period
- [ ] Step 6 completed: For ALL commits from additional repos, GitHub username obtained via GitHub CLI (not skipped). For commits with PR numbers, PR author used via `gh pr view` (not commit author)
- [ ] Step 7 completed: For EVERY PR in main repo (including backports), PR author obtained via `gh pr view <PR_NUMBER> --json author --jq .author.login` (not skipped or assumed). Commit author NOT used - always use PR author
- [ ] Step 7 completed: **Backports verified** - for each backport PR, original PR found and original PR author used in changelog
- [ ] Step 8 completed: Contributors list generated
- [ ] All commits from main repository included (including merge commits)
- [ ] User impact described for each change
- [ ] Format matches existing changelogs
**For patch releases:**
- [ ] All commits from the release period are included (including merge commits with backports)
- [ ] PR numbers match commit messages
- [ ] Backports are properly identified and linked to original PRs
**For minor releases (vX.Y.0):**
- [ ] All changes from patch releases (vX.Y.1, vX.Y.2, etc.) are included
- [ ] Contributors section is present and complete
- [ ] Full Changelog link references previous minor version (vX.Y.0), not last patch
- [ ] Verify all PRs from patch releases are included:
```bash
# Extract and compare PR numbers
PATCH_PRS=$(grep -hE "#[0-9]+" docs/changelogs/v<previous_minor>.*.md | grep -oE "#[0-9]+" | sort -u)
MINOR_PRS=$(grep -hE "#[0-9]+" docs/changelogs/v<new_minor>.0.md | grep -oE "#[0-9]+" | sort -u)
MISSING=$(comm -23 <(echo "$PATCH_PRS") <(echo "$MINOR_PRS"))
if [ -n "$MISSING" ]; then
echo "Missing PRs from patch releases:"
echo "$MISSING"
# For each missing PR, check if it's a backport and verify change is included by description
fi
```
**Only proceed to save after all checkboxes are verified!**
**Save the changelog:**
Save the changelog to file `docs/changelogs/v<version>.md` according to the version for which the changelog is being generated.
### Important notes
- **After fetch with --force** local tags are up-to-date, use them for work
- **For release branches** always check original commits in `main` to get correct PR numbers
- **Preserve the format** of existing changelog files
- **Group related changes** logically
- **Be accurate** in describing changes, based on actual commit diffs
- **Check for PR numbers** and commit authors
- **CRITICAL - Get authorship from PR, not from commit**:
- **ALWAYS use PR author**: Extract PR number from commit message, then use `gh pr view <PR_NUMBER> --json author --jq .author.login` to get the PR author
- Do NOT use commit author - the commit author (especially for squash/merge commits) is usually the person who merged the PR, not the person who wrote the code
- For commits without PR numbers (rare), fall back to commit author: `gh api repos/cozystack/cozystack/commits/<commit_hash> --jq '.author.login'`
- **Workflow**: Extract PR numbers from commits → Use `gh pr view` for each PR → Get PR author (the person who wrote the code)
- Example: For PR #1507, the commit author is `@kvaps` (who merged), but `gh pr view 1507 --json author --jq .author.login` correctly returns `@lllamnyp` (who wrote the code)
- Check existing changelogs for author name to GitHub username mappings
- **Validation**: Before adding to changelog, always verify the author using `gh pr view` - never use commit author for PRs
- **MANDATORY**: Always describe user impact: Every changelog entry must explain how the change affects end users, not just what was changed technically. Focus on user value and practical implications.
**Required steps:**
- **Additional repositories (Step 6) - MANDATORY**:
- **⚠️ CRITICAL**: Always check the **website** repository for documentation changes during the release period. This is a required step and MUST NOT be skipped.
- **⚠️ CRITICAL**: You MUST check ALL optional repositories (talm, boot-to-talos, cozyhr, cozy-proxy) for tags during the release period. Do NOT skip any repository even if you think there might not be tags.
- **CRITICAL**: For ALL entries from additional repositories (website and optional), you MUST:
- **MANDATORY**: Extract PR number from commit message first
- **MANDATORY**: For commits with PR numbers, ALWAYS use `gh pr view <PR_NUMBER> --repo cozystack/<repo> --json author --jq .author.login` to get PR author (not commit author)
- **MANDATORY**: Only for commits without PR numbers (rare), fallback to: `gh api repos/cozystack/<repo>/commits/<hash> --jq '.author.login'`
- **MANDATORY**: Do NOT skip getting GitHub username via CLI - do this for EVERY commit
- **MANDATORY**: Do NOT use commit author for PRs - always use PR author
- Include PR link or commit hash reference
- Format: `* **[repo] Description**: details ([**@username**](https://github.com/username) in cozystack/repo#123)`
- For **optional repositories** (talm, boot-to-talos, cozyhr, cozy-proxy), you MUST check ALL of them for tags during the release period. Use the loop provided in Step 6 to check each repository systematically.
- When including changes from additional repositories, use the format: `[repo-name] Description` and link to the repository's PR/issue if available
- **Prefer PR numbers over commit hashes**: For commits from additional repositories, extract PR number from commit message using GitHub API. Use PR format (`cozystack/website#123`) instead of commit hash (`cozystack/website@abc1234`) when available
- **Never add entries without author and PR/commit reference**: Every entry from additional repositories must have both author and link
- Group changes from additional repositories with main repository changes, or create separate subsections if there are many changes from a specific repository
- **PR author verification (Step 7) - MANDATORY**:
- **⚠️ CRITICAL**: You MUST get the author from PR using `gh pr view`, NOT from commit
- **⚠️ CRITICAL**: Extract PR numbers from commit messages, then use `gh pr view <PR_NUMBER> --json author --jq .author.login` for each PR
- **⚠️ CRITICAL**: Do NOT use commit author - commit author is usually the person who merged, not the person who wrote the code
- **⚠️ CRITICAL**: Do NOT skip this step for any PR, even if the author seems obvious
- For commits without PR numbers (rare), fall back to: `gh api repos/cozystack/cozystack/commits/<hash> --jq '.author.login'`
- This ensures correct attribution and prevents errors in changelog entries (especially important for squash/merge commits)
- **Contributors list (Step 8)**:
- For minor releases (vX.Y.0): You must generate a list of all contributors and identify first-time contributors.
- For patch releases: Contributors section is optional, but recommended for significant releases
- Extract GitHub usernames from PR links in commit messages or changelog entries
- This helps recognize community contributions and welcome new contributors
- **Minor releases (vX.Y.0)**:
- Must include **all changes** from patch releases of the previous minor version (e.g., v0.38.0 includes all changes from v0.37.1, v0.37.2, v0.37.3, etc.)
- The "Full Changelog" link must reference the previous minor release (v0.37.0...v0.38.0), NOT the last patch release (v0.37.8...v0.38.0)
- This ensures users can see the complete set of changes for the entire minor version cycle
- **Verification step**: After creating the changelog, extract all PR numbers from patch release changelogs and verify they all appear in the minor release changelog to prevent missing entries
- **Backport handling**: Patch releases may contain backports with different PR numbers (e.g., #1624 in patch release vs #1622 in main). For minor releases, use original PR numbers from main when available, but verify that all changes from patch releases are included regardless of PR number differences
- **Content verification**: Don't rely solely on PR number matching - verify that change descriptions from patch releases appear in the minor release changelog, as backports may have different PR numbers

View File

@@ -1,275 +0,0 @@
# Instructions for AI Agents
Guidelines for AI agents contributing to Cozystack.
## Checklist for Creating a Pull Request
- [ ] Changes are made and tested
- [ ] Commit message uses correct `[component]` prefix
- [ ] Commit is signed off with `--signoff`
- [ ] Branch is rebased on `upstream/main` (no extra commits)
- [ ] PR body includes description and release note
- [ ] PR is pushed and created with `gh pr create`
## How to Commit and Create Pull Requests
### 1. Make Your Changes
Edit the necessary files in the codebase.
### 2. Commit with Proper Format
Use the `[component]` prefix and `--signoff` flag:
```bash
git commit --signoff -m "[component] Brief description of changes"
```
**Component prefixes:**
- System: `[dashboard]`, `[platform]`, `[cilium]`, `[kube-ovn]`, `[linstor]`, `[fluxcd]`, `[cluster-api]`
- Apps: `[postgres]`, `[mysql]`, `[redis]`, `[kafka]`, `[clickhouse]`, `[virtual-machine]`, `[kubernetes]`
- Other: `[tests]`, `[ci]`, `[docs]`, `[maintenance]`
**Examples:**
```bash
git commit --signoff -m "[dashboard] Add config hash annotations to restart pods on config changes"
git commit --signoff -m "[postgres] Update operator to version 1.2.3"
git commit --signoff -m "[docs] Add installation guide"
```
### 3. Rebase on upstream/main (if needed)
If your branch has extra commits, clean it up:
```bash
# Fetch latest
git fetch upstream
# Create clean branch from upstream/main
git checkout -b my-feature upstream/main
# Cherry-pick only your commit
git cherry-pick <your-commit-hash>
# Force push to your branch
git push -f origin my-feature:my-branch-name
```
### 4. Push Your Branch
```bash
git push origin <branch-name>
```
### 5. Create Pull Request
Write the PR body to a temporary file:
```bash
cat > /tmp/pr_body.md << 'EOF'
## What this PR does
Brief description of the changes.
Changes:
- Change 1
- Change 2
### Release note
```release-note
[component] Description for changelog
```
EOF
```
Create the PR:
```bash
gh pr create --title "[component] Brief description" --body-file /tmp/pr_body.md
```
Clean up:
```bash
rm /tmp/pr_body.md
```
## Addressing AI Bot Reviewer Comments
When the user asks to fix comments from AI bot reviewers (like Qodo, Copilot, etc.):
### 1. Get PR Comments
View all comments on the pull request:
```bash
gh pr view <PR-number> --comments
```
Or for the current branch:
```bash
gh pr view --comments
```
### 2. Review Each Comment Carefully
**Important**: Do NOT blindly apply all suggestions. Each comment should be evaluated:
- **Consider context** - Does the suggestion make sense for this specific case?
- **Check project conventions** - Does it align with Cozystack patterns?
- **Evaluate impact** - Will this improve code quality or introduce issues?
- **Question validity** - AI bots can be wrong or miss context
**When to apply:**
- ✅ Legitimate bugs or security issues
- ✅ Clear improvements to code quality
- ✅ Better error handling or edge cases
- ✅ Conformance to project conventions
**When to skip:**
- ❌ Stylistic preferences that don't match project style
- ❌ Over-engineering simple code
- ❌ Changes that break existing patterns
- ❌ Suggestions that show misunderstanding of the code
### 3. Apply Valid Fixes
Make changes addressing the valid comments. Use your judgment.
### 4. Leave Changes Uncommitted
**Critical**: Do NOT commit or push the changes automatically.
Leave the changes in the working directory so the user can:
- Review the fixes
- Decide whether to commit them
- Make additional adjustments if needed
```bash
# After making changes, show status but DON'T commit
git status
git diff
```
The user will commit and push when ready.
## Code Review Comments
When asked to fix code review comments, **always work only with unresolved (open) comments**. Resolved comments should be ignored as they have already been addressed.
### Getting Unresolved Review Comments
Use GitHub GraphQL API to fetch only unresolved review comments from a pull request:
```bash
gh api graphql -F owner=cozystack -F repo=cozystack -F pr=<PR_NUMBER> -f query='
query($owner: String!, $repo: String!, $pr: Int!) {
repository(owner: $owner, name: $repo) {
pullRequest(number: $pr) {
reviewThreads(first: 100) {
nodes {
isResolved
comments(first: 100) {
nodes {
id
path
line
author { login }
bodyText
url
createdAt
}
}
}
}
}
}
}' --jq '.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved == false) | .comments.nodes[]'
```
### Filtering for Unresolved Comments
The key filter is `select(.isResolved == false)` which ensures only unresolved review threads are processed. Each thread can contain multiple comments, but if the thread is resolved, all its comments should be ignored.
### Working with Review Comments
1. **Fetch unresolved comments** using the GraphQL query above
2. **Parse the results** to identify:
- File path (`path`)
- Line number (`line` or `originalLine`)
- Comment text (`bodyText`)
- Author (`author.login`)
3. **Address each unresolved comment** by:
- Locating the relevant code section
- Making the requested changes
- Ensuring the fix addresses the concern raised
4. **Do NOT process resolved comments** - they have already been handled
### Example: Compact List of Unresolved Comments
For a quick overview of unresolved comments:
```bash
gh api graphql -F owner=cozystack -F repo=cozystack -F pr=<PR_NUMBER> -f query='
query($owner: String!, $repo: String!, $pr: Int!) {
repository(owner: $owner, name: $repo) {
pullRequest(number: $pr) {
reviewThreads(first: 100) {
nodes {
isResolved
comments(first: 100) {
nodes {
path
line
author { login }
bodyText
}
}
}
}
}
}
}' --jq '.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved == false) | .comments.nodes[] | "\(.path):\(.line // "N/A") - \(.author.login): \(.bodyText[:150])"'
```
### Important Notes
- **REST API limitation**: The REST endpoint `/pulls/{pr}/reviews` returns review summaries, not individual review comments. Use GraphQL API for accessing `reviewThreads` with `isResolved` status.
- **Thread-based resolution**: Comments are organized in threads. If a thread is resolved (`isResolved: true`), ignore all comments in that thread.
- **Always filter**: Never process comments from resolved threads, even if they appear in the results.
### Example Workflow
```bash
# Get PR comments
gh pr view 1234 --comments
# Review comments and identify valid ones
# Make necessary changes to address valid comments
# ... edit files ...
# Show what was changed (but don't commit)
git status
git diff
# Tell the user what was fixed and what was skipped
```
## Git Permissions
Request these permissions when needed:
- `git_write` - For commit, rebase, cherry-pick, branch operations
- `network` - For push, fetch, pull operations
## Common Issues
**PR has extra commits?**
→ Rebase on `upstream/main` and cherry-pick only your commits
**Wrong commit message?**
`git commit --amend --signoff -m "[correct] message"` then `git push -f`
**Need to update PR?**
`gh pr edit <number> --body "new description"`

View File

@@ -1,115 +0,0 @@
# Cozystack Project Overview
This document provides detailed information about Cozystack project structure and conventions for AI agents.
## About Cozystack
Cozystack is an open-source Kubernetes-based platform and framework for building cloud infrastructure. It provides:
- **Managed Services**: Databases, VMs, Kubernetes clusters, object storage, and more
- **Multi-tenancy**: Full isolation and self-service for tenants
- **GitOps-driven**: FluxCD-based continuous delivery
- **Modular Architecture**: Extensible with custom packages and services
- **Developer Experience**: Simplified local development with cozyhr tool
The platform exposes infrastructure services via the Kubernetes API with ready-made configs, built-in monitoring, and alerts.
## Code Layout
```
.
├── packages/ # Main directory for cozystack packages
│ ├── core/ # Core platform logic charts (installer, platform)
│ ├── system/ # System charts (CSI, CNI, operators, etc.)
│ ├── apps/ # User-facing charts shown in dashboard catalog
│ └── extra/ # Tenant-specific modules, singleton charts which are used as dependencies
├── dashboards/ # Grafana dashboards for monitoring
├── hack/ # Helper scripts for local development
│ └── e2e-apps/ # End-to-end application tests
├── scripts/ # Scripts used by cozystack container
│ └── migrations/ # Version migration scripts
├── docs/ # Documentation
│ ├── agents/ # AI agent instructions
│ └── changelogs/ # Release changelogs
├── cmd/ # Go command entry points
│ ├── cozystack-api/
│ ├── cozystack-controller/
│ └── cozystack-assets-server/
├── internal/ # Internal Go packages
│ ├── controller/ # Controller implementations
│ └── lineagecontrollerwebhook/
├── pkg/ # Public Go packages
│ ├── apis/
│ ├── apiserver/
│ └── registry/
└── api/ # Kubernetes API definitions (CRDs)
└── v1alpha1/
```
## Package Structure
Every package is a Helm chart following the umbrella chart pattern:
```
packages/<category>/<package-name>/
├── Chart.yaml # Chart definition and parameter docs
├── Makefile # Development workflow targets
├── charts/ # Vendored upstream charts
├── images/ # Dockerfiles and image build context
├── patches/ # Optional upstream chart patches
├── templates/ # Additional manifests
├── templates/dashboard-resourcemap.yaml # Dashboard resource mapping
├── values.yaml # Override values for upstream
└── values.schema.json # JSON schema for validation and UI
```
## Conventions
### Helm Charts
- Follow **umbrella chart** pattern for system components
- Include upstream charts in `charts/` directory (vendored, not referenced)
- Override configuration in root `values.yaml`
- Use `values.schema.json` for input validation and dashboard UI rendering
### Go Code
- Follow standard **Go conventions** and idioms
- Use **controller-runtime** patterns for Kubernetes controllers
- Prefer **kubebuilder** for API definitions and controllers
- Add proper error handling and structured logging
### Git Commits
- Use format: `[component] Description`
- Always use `--signoff` flag
- Reference PR numbers when available
- Keep commits atomic and focused
- Follow conventional commit format for changelogs
### Documentation
Documentation is organized as follows:
- `docs/` - General documentation
- `docs/agents/` - Instructions for AI agents
- `docs/changelogs/` - Release changelogs
- Main website: https://github.com/cozystack/website
## Things Agents Should Not Do
### Never Edit These
- Do not modify files in `/vendor/` (Go dependencies)
- Do not edit generated files: `zz_generated.*.go`
- Do not change `go.mod`/`go.sum` manually (use `go get`)
- Do not edit upstream charts in `packages/*/charts/` directly (use patches)
- Do not modify image digests in `values.yaml` (generated by build)
### Version Control
- Do not commit built artifacts from `_out`
- Do not commit test artifacts or temporary files
### Git Operations
- Do not force push to main/master
- Do not update git config
- Do not perform destructive operations without explicit request
### Core Components
- Do not modify `packages/core/platform/` without understanding migration impact

View File

@@ -1,29 +0,0 @@
# Release Process
This document provides instructions for AI agents on how to handle release-related tasks.
## When to Use
Follow these instructions when the user asks to:
- Create a new release
- Prepare a release
- Tag a release
- Perform release-related tasks
## Instructions
For detailed release process instructions, follow the steps documented in:
**[docs/release.md](../release.md)**
## Quick Reference
The release process typically involves:
1. Preparing the release branch
2. Generating changelog
3. Updating version numbers
4. Creating git tags
5. Building and publishing artifacts
All detailed steps are documented in `docs/release.md`.

View File

@@ -1,18 +0,0 @@
<!--
https://github.com/cozystack/cozystack/releases/tag/v0..
-->
## Features and Improvements
## Security
## Fixes
## Dependencies
## Development, Testing, and CI/CD
---
**Full Changelog**: https://github.com/cozystack/cozystack/compare/v0.36.0...main

View File

@@ -17,4 +17,4 @@ https://github.com/cozystack/cozystack/releases/tag/v0..
---
**Full Changelog**: https://github.com/cozystack/cozystack/compare/v0.34.0...v0.35.0
**Full Changelog**: **Full Changelog**: https://github.com/cozystack/cozystack/compare/v0.34.0...v0.35.0

View File

@@ -0,0 +1,3 @@
# Changes after v0.37.0
* [lineage] Break webhook out into a separate daemonset. Reduce unnecessary webhook calls by marking handled resources and excluding them from consideration by the webhook's object selector (@lllamnyp in #1515).

View File

@@ -1,10 +0,0 @@
<!--
https://github.com/cozystack/cozystack/releases/tag/v0.35.3
-->
## Fixes
* [seaweedfs] Add a liveness check for the SeaweedFS S3 endpoint to improve health monitoring and enable automatic recovery. (@IvanHunters in https://github.com/cozystack/cozystack/pull/1368)
**Full Changelog**: https://github.com/cozystack/cozystack/compare/v0.35.2...v0.35.3

View File

@@ -1,14 +0,0 @@
<!--
https://github.com/cozystack/cozystack/releases/tag/v0.35.4
-->
## Fixes
* [virtual-machine] Fix the regression in VM update hook introduced in https://github.com/cozystack/cozystack/pull/1169 by targeting the correct API resource and avoiding conflicts with KubeVirt resources. (@kvaps in https://github.com/cozystack/cozystack/pull/1376, backported in https://github.com/cozystack/cozystack/pull/1377)
* [cozy-lib] Add the missing template `cozy-lib.resources.flatten`. (@kvaps in https://github.com/cozystack/cozystack/pull/1372, backported in https://github.com/cozystack/cozystack/pull/1375)
* [platform] Fix a boolean override bug in Helm merge. ConfigMap values now correctly take precedence over bundle defaults. (@dyudin0821 in https://github.com/cozystack/cozystack/pull/1385, backported in https://github.com/cozystack/cozystack/pull/1388)
* [seaweedfs] Resolve connectivity issues in SeaweedFS. Increase Nginx ingress timeouts for SeaweedFS S3 endpoint. (@kvaps in https://github.com/cozystack/cozystack/pull/1386, backported in https://github.com/cozystack/cozystack/pull/1390)
* [dx] Remove the BUILDER and PLATFORM autodetect logic in Makefiles. (@kvaps in https://github.com/cozystack/cozystack/pull/1391, backported in https://github.com/cozystack/cozystack/pull/1392)
**Full Changelog**: https://github.com/cozystack/cozystack/compare/v0.35.3...v0.35.4

View File

@@ -1,11 +0,0 @@
<!--
https://github.com/cozystack/cozystack/releases/tag/v0.35.5
-->
## Fixes
* [etcd] Ensure that TopologySpreadConstraints consistently target etcd pods. (@kvaps in https://github.com/cozystack/cozystack/pull/1405, backported in https://github.com/cozystack/cozystack/pull/1406)
* [tests] Add resource quota for testing namespaces. (@IvanHunters in https://github.com/cozystack/cozystack/commit/4982cdf5024c8bb9aa794b91d55545ea6b105d17)
**Full Changelog**: https://github.com/cozystack/cozystack/compare/v0.35.4...v0.35.5

View File

@@ -1,117 +0,0 @@
<!--
https://github.com/cozystack/cozystack/releases/tag/v0.36.0
-->
## Feature Highlights
Release v0.36.0 focuses on the stability, observability, and flexible configuration of managed applications.
### Per-Namespace Resource Limits for Tenants
Resource management for Cozystack tenants has received a final patch and is now graduated to a stable feature.
Platform administrators can define explicit CPU, memory, and storage limits for each tenant's namespace
via the tenant specification.
This prevents any single tenant from consuming more than their share of cluster resources,
ensuring cluster stability and a guaranteed service level for each tenant.
### Kube-OVN Cluster Health Monitor
A new component called the Kube-OVN Plunger continuously monitors the health of the Kube-OVN network's central control cluster.
This external agent gathers OVN cluster status and consensus information, exposing Prometheus metrics and live events stream via SSE.
As a result, it provides much better visibility of the virtual network layer and helps maintain a reliable and observable network in Cozystack.
This change opens the road to automated Kube-OVN database operations and recovery in specific corner cases.
### Configurable CoreDNS Addon for Kubernetes
Cozystack introduces a dedicated CoreDNS addon for managing cluster DNS with greater flexibility.
CoreDNS is now deployed via a Helm chart and can be tuned through custom values in the cluster specification,
including autoscaling, replica count, and adjusting service IP.
CoreDNS can now be configured in the dashboard and using Cozystack API.
### Granular SeaweedFS Service Configuration
The SeaweedFS S3 storage service in Cozystack is now far more configurable at a component level.
The Helm chart for SeaweedFS now includes independent configuration for each component and its resources.
It includes the master nodes, volume servers with support for multiple zones, filers, the backing database, and the S3 gateway.
Administrators can set per-component parameters such as the number of replicas, available CPU, memory, and storage size.
### Server-side Encryption for S3
Cozystack v0.36.0 includes SeaweedFS 3.97, bringing support for server-side encryption of S3 buckets (SSE-C, SSE-KMS, and SSE-S3).
**Breaking change:** upon updating Cozystack, SeaweedFS will be updated to a newer version, and the services specification
will be converted to the new format.
### Custom Resource Profiles for Ingress Controller
NGINX controller is now configurable on a per-replica basis.
Configurations include the ingress controller pods' CPU and memory requests/limits, either with direct values or using one of the available presets.
### Cozystack REST API Documentation
[Cozystack REST API reference](https://cozystack.io/docs/cozystack-api/rest/) is now published on the website.
It includes endpoints and methods for listing, creating, updating, and removing each managed application, defined as Cozystack CRD.
### Built-in LLDP-Based Neighbor Discovery in Talos
Cozystack now includes the LLDPD extension in its Talos OS image, enabling Link Layer Discovery Protocol (LLDP) out of the box.
This means each node can automatically discover and advertise its network neighbors and topology without any manual setup.
### Use external IP for Egress Traffic in VMs
When a virtual machine has an external IP assigned to it, it will now always use it for egress traffic, independently of the external method used.
## Major Features and Improvements
* [talos] Add LLDPD (`ghcr.io/siderolabs/lldpd`) as a built-in system extension, enabling LLDP-based neighbor discovery out of the box. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1351 and https://github.com/cozystack/cozystack/pull/1360)
* [kubernetes] Add a configurable CoreDNS addon with valuesOverride, packaged chart, and managed deployment (metrics, autoscaling, HPA, customizable Service). (@klinch0 in https://github.com/cozystack/cozystack/pull/1362)
* [kube-ovn] Implement the Kube-OVN plunger, an external monitoring agent for the ovn-central cluster. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1380, patched in https://github.com/cozystack/cozystack/pull/1414 and https://github.com/cozystack/cozystack/pull/1418)
* [tenant] Enable per-namespace resource quota settings in tenants, with explicit cpu, memory, and storage values. (@IvanHunters in https://github.com/cozystack/cozystack/pull/1389)
* [seaweedfs] Add detailed resource configuration for each component of the SeaweedFS service. (@klinch0 and @kvaps in https://github.com/cozystack/cozystack/pull/1415)
* [ingress] Enable per-replica resource configuration to the ingress controller. (@kvaps in https://github.com/cozystack/cozystack/pull/1416)
* [virtual-machine] Use external IP for egress traffic with `PortList` method. (@kvaps in https://github.com/cozystack/cozystack/pull/1349)
## Fixes
* [cozy-lib] Fix malformed retrieval of `cozyConfig` in the cozy-lib template. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1348)
* [cozy-lib] Add the missing template `cozy-lib.resources.flatten`. (@kvaps in https://github.com/cozystack/cozystack/pull/1372)
* [cozystack-api] Sanitize the OpenAPI v2 schema. (@kvaps in https://github.com/cozystack/cozystack/pull/1353)
* [kube-ovn] Improve northd leader detection. Patch the northd leader check to test against all endpoints instead of just the first one marked as ready. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1363)
* [seaweedfs] Add a liveness check for the SeaweedFS S3 endpoint to improve health monitoring and enable automatic recovery. (@IvanHunters in https://github.com/cozystack/cozystack/pull/1368)
* [seaweedfs] Resolve race conditions in SeaweedFS. Increase deployment timeouts and set install/upgrade remediation to unlimited retries to improve deployment resilience. (@IvanHunters in https://github.com/cozystack/cozystack/pull/1371)
* [seaweedfs] Resolve connectivity issues in SeaweedFS. Increase Nginx ingress timeouts for SeaweedFS S3 endpoint. (@kvaps in https://github.com/cozystack/cozystack/pull/1386)
* [virtual-machine] Fix the reg ression in VM update hook introduced in https://github.com/cozystack/cozystack/pull/1169. Target the correct API resource and avoid conflicts with KubeVirt resources. (@kvaps in https://github.com/cozystack/cozystack/pull/1376)
* [virtual-machine] Correct app version references in `virtual-machine` and `vm-instance`, ensuring accurate versioning during migrations. (@kvaps in https://github.com/cozystack/cozystack/pull/1378).
* [cozyreport] Fix an error where cozyreport tried to parse non-existent objects and generated garbage output in CI debug logs. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1383)
* [platform] Fix a boolean override bug in Helm merge. ConfigMap values now correctly take precedence over bundle defaults. (@dyudin0821 in https://github.com/cozystack/cozystack/pull/1385)
* [kubernetes] CoreDNS release now installs and stores state in the `kube-system` namespace. (@kvaps in https://github.com/cozystack/cozystack/pull/1395)
* [kubernetes] Expose configuration for CoreDNS, enabling setting the image repository and replica count via `values.yaml`. (@kvaps in https://github.com/cozystack/cozystack/pull/1410)
* [etcd] Ensure that TopologySpreadConstraints consistently target etcd pods. (@kvaps in https://github.com/cozystack/cozystack/pull/1405)
* [tenant] Use force-upgrade for ingress controller charts. (@klinch0 in https://github.com/cozystack/cozystack/pull/1404)
* [cozystack-controller] Fix an RBAC error that prevented the workload labelling feature from working. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1419)
* [seaweedfs] Remove VerticalPodAutoscaler for SeaweedFS. (@kvaps in https://github.com/cozystack/cozystack/pull/1421)
## Dependencies
* Update LINSTOR to v1.31.3. (@kvaps in https://github.com/cozystack/cozystack/pull/1358)
* Update SeaweedFS to v3.97. (@kvaps in https://github.com/cozystack/cozystack/pull/1361 and https://github.com/cozystack/cozystack/pull/1373)
* Update Kube-OVN to 1.14.5. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1363)
* Replace Bitnami images with alternatives in all charts. (@kvaps in https://github.com/cozystack/cozystack/pull/1374)
## Documentation
## Development, Testing, and CI/CD
* [dx] Remove the BUILDER and PLATFORM autodetect logic in Makefiles. (@kvaps in https://github.com/cozystack/cozystack/pull/1391)
* [ci] Use the host buildx config in CI. (@kvaps in https://github.com/cozystack/cozystack/pull/1015)
* [ci] Add `jq` and `git` to the installer image. (@kvaps in https://github.com/cozystack/cozystack/pull/1417)
* [ci] Source the `REGISTRY` environment variable from actions' variables, not secrets, so external pull requests can work. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1423)
---
**Full Changelog**: https://github.com/cozystack/cozystack/compare/v0.35.0...v0.36.0

View File

@@ -1,22 +0,0 @@
<!--
https://github.com/cozystack/cozystack/releases/tag/v0.36.1
-->
## Major Features and Improvements
* [cozystack-api] Implement recursive, Kubernetes-like defaulting for applications: missing fields in nested objects and arrays are auto-populated safely without mutating shared defaults. (@kvaps in https://github.com/cozystack/cozystack/pull/1432)
## Fixes
* [cozystack-api] Update defaulting API schemas. (@kvaps in https://github.com/cozystack/cozystack/pull/1433)
* [dashboard] Fix Bitnami dependencies. (@kvaps in https://github.com/cozystack/cozystack/pull/1431)
* [seaweedfs] Fix SeaweedFS migration. (@kvaps in https://github.com/cozystack/cozystack/pull/1430)
## Development, Testing, and CI/CD
* [adopters] Add [Hidora](https://hikube.cloud) to the Cozystack adopters list. (@matthieu-robin in https://github.com/cozystack/cozystack/pull/1429)
---
**Full Changelog**: https://github.com/cozystack/cozystack/compare/v0.36.0...v0.36.1

View File

@@ -1,21 +0,0 @@
<!--
https://github.com/cozystack/cozystack/releases/tag/v0.36.2
-->
## Features and Improvements
* [vm-disk] New SVG icon for VM disk application. (@kvaps and @kvapsova in https://github.com/cozystack/cozystack/pull/1435)
## Fixes
* [kubernetes] Pin CoreDNS image tag to v1.12.4 for consistent, reproducible deployments. (@kvaps in https://github.com/cozystack/cozystack/pull/1469)
* [dashboard] Fix FerretDB spec typo that prevented deploy/display in the web UI. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1440)
## Dependencies
## Development, Testing, and CI/CD
---
**Full Changelog**: [v0.36.1...v0.36.2](https://github.com/cozystack/cozystack/compare/v0.36.1...v0.36.2)

View File

@@ -1,117 +0,0 @@
# Cozystack v0.37 — “OpenAPI Dashboard & Lineage Everywhere”
Weve shipped a big usability push this cycle: a brand-new **OpenAPI-driven dashboard**, lineage labeling across core resource types, and several reliability improvements to smooth upgrades from 0.36→ 0.37. Below are the highlights and the full categorized lists.
## Highlights
* **New OpenAPI-based Dashboard** replaces the old UI, adds module-aware navigation, dynamic branding, and richer Kubernetes resource views ([**@kvaps**](https://github.com/kvaps) in #1269, #1463, #1460).
* **Lineage Webhook** tags Pods, PVCs, Services, Ingresses, and Secrets, adding labels referencing the managing Cozystack application ([**@lllamnyp**](https://github.com/lllamnyp) in #1448, #1452, #1477, #1486, #1497; [**@kvaps**](https://github.com/kvaps) in #1454).
* **Smoother upgrades** with installer and migration hardening, decoupled CRDs vs. API server ([**@lllamnyp**](https://github.com/lllamnyp) in #1494, #1498; [**@kvaps**](https://github.com/kvaps) in #1506).
* **Operations quality**: Kubernetes tests with smarter waits/readiness checks ([**@IvanHunters**](https://github.com/IvanHunters) in #1485).
---
## New features
### Dashboard
* Introduce the OpenAPI-based dashboard and controller; implement TenantNamespace, TenantModules, TenantSecret/SecretsTable resources ([**@kvaps**](https://github.com/kvaps) in #1269).
* Module-aware navigation, richer detail views (Services/Secrets/Ingresses), improved sidebars; “Tenant Modules” grouping ([**@kvaps**](https://github.com/kvaps) in #1463).
* Dynamic branding via cluster config (tenant name, footer/title, logo/icon SVGs) ([**@kvaps**](https://github.com/kvaps) in #1460).
* Dashboard: fix namespace listing for unprivileged users and stabilize streamed requests; build-time patching ([**@kvaps**](https://github.com/kvaps) in #1456).
* Dashboard UX set: marketplace hides module resources; consistent navigation/links; prefill “name” in forms; ingress factory; formatted TenantNamespaces tables ([**@kvaps**](https://github.com/kvaps) in #1463).
* **Dashboard**: list modules reliably; remove Tenant from Marketplace; fix field override while typing ([**@kvaps**](https://github.com/kvaps) in #1501, #1503).
* **Dashboard**: correct API group for applications; sidebars; disable auto-expand; fix `/docs` redirect ([**@kvaps**](https://github.com/kvaps) in #1463, #1465, #1462).
* **Dashboard**: show Secrets with empty values correctly ([**@kvaps**](https://github.com/kvaps) in #1480).
* Dashboard configuration refactor: generate static resources at startup; auto-cleanup stale objects; higher controller client throughput ([**@kvaps**](https://github.com/kvaps) in #1457).
### Migration to v0.37
* **Installer/Migrations**: prevent unintended deletion of platform resource definitions; resilient timestamping; tolerant annotations; stronger migrate-then-reconcile flow ([**@kvaps**](https://github.com/kvaps) in #1475; Andrei Kvapil & [**@lllamnyp**](https://github.com/lllamnyp) in #1498).
* Installer hardening for **migration #20**: packaged apply, ordered waits/readiness checks, RFC3339(nano) stamping; Helm in installer image (Andrei Kvapil & [**@lllamnyp**](https://github.com/lllamnyp) in #1498).
* **Decoupled API & CozyRDs**: You can now upgrade the Cozystack API server independently of CRDs/CozyRD instances, easing 0.36 → 0.37 migrations ([**@lllamnyp**](https://github.com/lllamnyp) in #1494).
* **Migration #20**: The installer runs migration from packaged Helm charts with ordered waits/readiness checks; annotations are tolerant; timestamps are environment-robust (Andrei Kvapil & [**@lllamnyp**](https://github.com/lllamnyp) in #1498; [**@kvaps**](https://github.com/kvaps) in #1475).
### Webhook / Lineage
* Add a lineage mutating webhook to auto-label Pods/Secrets/PVCs/Ingresses/WorkloadMonitors with owning app ([**@lllamnyp**](https://github.com/lllamnyp) in #1448, #1497, [**@kvaps**](https://github.com/kvaps) in #1454).
* **Name-based** selectors for Secret visibility (templates supported) ([**@lllamnyp**](https://github.com/lllamnyp) in #1477).
* Select **Services** and **Ingresses** in CRDs/API; treat them as user-facing when configured ([**@lllamnyp**](https://github.com/lllamnyp) in #1486).
* **VictoriaMetrics integration**: Lineage labels are explicitly set on VM resources; `managedMetadata` is configured to avoid controller “fights” over labels ([**@lllamnyp**](https://github.com/lllamnyp) in #1452).
* Webhook **excludes** `default` and `kube-system` to avoid unintended mutations (part of the installer/migration hardening by Andrei Kvapil & [**@lllamnyp**](https://github.com/lllamnyp) in #1498).
### API / Platform
* Decouple the Cozystack API from Cozystack Resource Definitions to allow independent upgrades ([**@lllamnyp**](https://github.com/lllamnyp) in #1494).
* Add **label selectors** to app definitions for Secret include/exclude ([**@lllamnyp**](https://github.com/lllamnyp) in #1447).
### Monitoring & Ops
* Reduce node labelsets in target relabeling configs on cadvisor/kubelet metrics to reduce cardinality while keeping useful CPU metrics ([**@IvanHunters**](https://github.com/IvanHunters) in #1455).
### Storage & Backups
* PVC expansion in tenant clusters via KubeVirt CSI resizer; RBAC updates (Klinch0 in #1438).
* Velero upgraded to **v1.17.0**; node agent enabled by default and a raft of usability features ([**@kvaps**](https://github.com/kvaps) in #1484).
### Kubernetes/tests & Tooling
* Smarter Kubernetes test flows: node readiness checks, kubelet version validation, longer rollout waits, per-component readiness ([**@IvanHunters**](https://github.com/IvanHunters) in #1485).
### UI/Icons
* New **VM-Disk** SVG icon ([**@kvapsova**](https://github.com/kvapsova) in #1435).
---
## Improvements (minor)
* Make the **Info** app deploy irrespective of OIDC settings ([**klinch0**](https://github.com/klinch0) in #1474).
* Move SA token Secret creation to **Info** app ([**@lllamnyp**](https://github.com/lllamnyp) in #1446).
* Explicitly set lineage labels for VictoriaMetrics resources ([**@lllamnyp**](https://github.com/lllamnyp) in #1452).
---
## Bug fixes
* **Kubernetes**: fix MachineDeployment `spec.selector` mismatch to ensure proper targeting ([**@kvaps**](https://github.com/kvaps) in #1502).
* **Old dashboard**: FerretDB spec typo prevented deploy/display ([**@lllamnyp**](https://github.com/lllamnyp) in #1440).
* **SeaweedFS**: fix per-zone size fallback for multi-DC volumes; make migrations more robust ([**@kvaps**](https://github.com/kvaps) in #1476, #1430).
* **CoreDNS**: pin tag to v1.12.4 ([**@kvaps**](https://github.com/kvaps) in #1469).
* **OIDC**: avoid creating KeycloakRealmGroup before operator API is available ([**@lllamnyp**](https://github.com/lllamnyp) in #1495).
* **Kafka**: disable noisy alerts when Kafka isnt deployed ([**@lllamnyp**](https://github.com/lllamnyp) in #1488).
---
## Dependency & version updates
* **Velero → v1.17.0**; Helm chart v11; node agent default-on ([**@kvaps**](https://github.com/kvaps) in #1484).
* **Cilium → v1.17.8** ([**@kvaps**](https://github.com/kvaps) in #1473).
* **Flux Operator → v0.29.0** (Kingdon Barrett in #1466).
---
## Refactors & chores
* Remove legacy `versions_map`; unify packaging targets; tighten HelmRelease defaults; replace many chart versions with build-time placeholders ([**@kvaps**](https://github.com/kvaps) in #1453).
* Pin CoreDNS image and refresh numerous images ([**@kvaps**](https://github.com/kvaps) in #1469; related image refreshes across #1448 work).
---
## Documentation & governance
* **Contributor Ladder** created and later updated (Timur Tukaev in #1224; Andrei Kvapil & Timur Tukaev in #1492).
* **Code of Conduct** updated with a Vendor Neutrality Manifesto (Timur Tukaev in #1493).
* **Adopters**: add Hidora (Matthieu Robin in #1429).
* **MAINTAINERS**: add/remove entries (Nikita Bykov in #1487; Timur Tukaev in #1491).
* **Issue templates**: new bug-report template and tweaks (Moriarti).
* **README**: updated dark-theme screenshot ([**@kvaps**](https://github.com/kvaps) in #1459).
---
## Breaking changes & upgrade notes
---
## Security & stability

View File

@@ -1,31 +0,0 @@
<!--
https://github.com/cozystack/cozystack/releases/tag/v0.37.1
-->
## Features and Improvements
* **[api] Efficient listing of TenantNamespaces**: Optimized TenantNamespace listing by replacing per-namespace SubjectAccessReview calls with group-based rolebinding checks, significantly reducing API latency and improving performance ([**@lllamnyp**](https://github.com/lllamnyp) in #1507).
## Fixes
* **[api] Fix RBAC for listing of TenantNamespaces and handle system:masters**: Fixed regression in TenantNamespace listing RBAC and added proper handling for system:masters group to ensure correct authorization ([**@kvaps**](https://github.com/kvaps) in #1511).
* **[dashboard] Fix logout**: Fixed dashboard logout functionality to properly clear session and redirect users ([**@kvaps**](https://github.com/kvaps) in #1510).
* **[installer] Add additional check to wait for lineage-webhook**: Added additional readiness check to ensure lineage-webhook is fully ready before proceeding with installation, improving upgrade reliability ([**@kvaps**](https://github.com/kvaps) in #1506).
## Development, Testing, and CI/CD
* **[tests] Make Kubernetes tests POSIX-compatible**: Replaced bash-specific constructs with POSIX-compliant code, ensuring tests work reliably with /bin/sh and improving compatibility across different shell environments ([**@IvanHunters**](https://github.com/IvanHunters) in #1509).
## Documentation
* **[website] Update troubleshooting documentation**: Updated Kubernetes installation troubleshooting guide with additional information and fixes ([**@lb0o**](https://github.com/lb0o) in cozystack/website@82beddd).
* **[website] Add LLDPD disabling documentation**: Added minimal patch documentation for disabling lldpd based on official LLDPD usage guide ([**@lb0o**](https://github.com/lb0o) in cozystack/website@7ec5d7b).
* **[website] Fix typo in utility command**: Fixed typo in utility command documentation ([**@lb0o**](https://github.com/lb0o) in cozystack/website@6c76cb5).
* **[website] Update backup and recovery docs**: Updated backup and recovery documentation with latest information ([**@kvaps**](https://github.com/kvaps) in cozystack/website@2781aa5).
* **[website] Add Troubleshooting checklist**: Added troubleshooting checklist to help users diagnose and resolve common issues ([**@kvaps**](https://github.com/kvaps) in cozystack/website@59fc304).
---
**Full Changelog**: [v0.37.0...v0.37.1](https://github.com/cozystack/cozystack/compare/v0.37.0...v0.37.1)

View File

@@ -1,21 +0,0 @@
<!--
https://github.com/cozystack/cozystack/releases/tag/v0.37.2
-->
## Features and Improvements
* **[lineage] Separate webhook from cozy controller**: Separated the lineage-controller-webhook from cozystack-controller into a separate daemonset component deployed on all control-plane nodes, reducing API server latency and improving performance by decreasing outgoing API calls. Introduced internal label to track resources already handled by the webhook ([**@lllamnyp**](https://github.com/lllamnyp) in #1515).
## Fixes
* **[api] Fix listing tenantnamespaces for non-oidc users**: Fixed TenantNamespace listing functionality for users not using OIDC authentication, ensuring proper namespace visibility for all authentication methods ([**@kvaps**](https://github.com/kvaps) in #1517, #1519).
## Migration and Upgrades
* **[platform] Better migration for 0.36.2->0.37.2+**: Improved migration script for users upgrading directly from 0.36.2 to 0.37.2+, ensuring the new lineage webhook daemonset is properly deployed and fixing a bug where webhook readiness was not appropriately verified during migration ([**@lllamnyp**](https://github.com/lllamnyp) in #1521, #1522).
---
**Full Changelog**: [v0.37.1...v0.37.2](https://github.com/cozystack/cozystack/compare/v0.37.1...v0.37.2)

View File

@@ -1,45 +0,0 @@
<!--
https://github.com/cozystack/cozystack/releases/tag/v0.37.3
-->
## Features and Improvements
* **[apps] Make VM service user facing**: Virtual machine services are now marked as user-facing, improving service discovery and visibility in the dashboard ([**@lllamnyp**](https://github.com/lllamnyp) in #1523).
* **[seaweedfs] Allow users to discover their buckets**: Users can now discover and list their S3 buckets in SeaweedFS, improving usability and bucket management ([**@kvaps**](https://github.com/kvaps) in #1528).
* **[seaweedfs] Update SeaweedFS v3.99 and deploy S3 as stacked service**: Updated SeaweedFS to version 3.99 and deployed S3 gateway as a stacked service for better integration and performance ([**@kvaps**](https://github.com/kvaps) in #1562).
* **[dashboard] Show service LB IP**: Fixed JSON path issue to correctly display Service LoadBalancer IPs in the dashboard table view, improving visibility of service endpoints ([**@lllamnyp**](https://github.com/lllamnyp) in #1524).
* **[dashboard] Update openapi-ui v1.0.3 + fixes**: Updated OpenAPI UI to version 1.0.3 with various fixes and improvements ([**@kvaps**](https://github.com/kvaps) in #1564).
* **[kubernetes] Use controlPlane.replicas field**: Fixed managed Kubernetes app to properly use the `controlPlane.replicas` field instead of hardcoding the value, allowing users to configure control plane replica count ([**@lllamnyp**](https://github.com/lllamnyp) in #1556).
* **[monitoring] add settings alert for slack**: Added Slack integration configuration for Alerta alerts, enabling notifications to Slack channels ([**@scooby87**](https://github.com/scooby87) in #1545).
## Fixes
* **[lineage] Check for nil chart in HelmRelease**: Added nil check to prevent crashes when lineage webhook encounters HelmReleases using `chartRef` instead of `chart`, improving stability ([**@lllamnyp**](https://github.com/lllamnyp) in #1525).
* **[kamaji] Respect 3rd party labels**: Applied patch to Kamaji controller to respect third-party labels, preventing reconciliation loops between lineage webhook and Kamaji controller ([**@lllamnyp**](https://github.com/lllamnyp) in #1531, #1534).
* **[redis-operator] Build patched operator in-tree**: Moved Redis operator build into Cozystack organization and patched it to prevent overwriting third-party labels on owned resources ([**@lllamnyp**](https://github.com/lllamnyp) in #1547).
* **[mariadb-operator] Add post-delete job to remove PVCs**: Added post-delete job to automatically remove PersistentVolumeClaims when MariaDB instances are deleted, preventing orphaned storage resources ([**@IvanHunters**](https://github.com/IvanHunters) in #1553).
* **[velero] Set defaultItemOperationTimeout=24h**: Set default item operation timeout to 24 hours for Velero backups, preventing timeouts on large backup operations ([**@kvaps**](https://github.com/kvaps) in #1542).
## Dependencies
* **Update LINSTOR v1.32.3**: Updated LINSTOR to version 1.32.3 with latest features and bug fixes ([**@kvaps**](https://github.com/kvaps) in #1565).
## System Configuration
* **[system] kube-ovn: turn off enableLb**: Disabled load balancer functionality in Kube-OVN configuration ([**@nbykov0**](https://github.com/nbykov0) in #1548).
## Documentation
* **[website] Update LINSTOR documentation**: Updated LINSTOR guide and set failmode=continue for ZFS configurations ([**@kvaps**](https://github.com/kvaps) in cozystack/website@033804e).
* **[website] Update managed apps reference**: Updated managed applications reference documentation ([**@kvaps**](https://github.com/kvaps) in cozystack/website@b886a74).
* **[website] Update external apps documentation**: Updated documentation for external applications ([**@kvaps**](https://github.com/kvaps) in cozystack/website@565dad9).
* **[website] Add naming conventions**: Added naming conventions documentation ([**@kvaps**](https://github.com/kvaps) in cozystack/website@b227abb).
* **[website] Update golden image documentation**: Updated documentation for creating golden images for virtual machines ([**@kvaps**](https://github.com/kvaps) in cozystack/website@34c2f3a, cozystack/website@ef65593).
* **[website] Fix documentation formatting**: Fixed alerts, infoboxes, tabs styles and main page formatting ([**@kvaps**](https://github.com/kvaps) in cozystack/website@e992e97, cozystack/website@b2c4dee).
* **[website] Fix typo in blog article**: Fixed typo in blog article ([**@kvaps**](https://github.com/kvaps) in cozystack/website@0a4bbf3).
---
**Full Changelog**: [v0.37.2...v0.37.3](https://github.com/cozystack/cozystack/compare/v0.37.2...v0.37.3)

View File

@@ -1,29 +0,0 @@
<!--
https://github.com/cozystack/cozystack/releases/tag/v0.37.4
-->
## Features and Improvements
* **[tenant] Allow listing workloads**: Enabled listing of workloads for tenants, improving visibility and management of tenant resources ([**@kvaps**](https://github.com/kvaps) in #1576, #1577).
## Fixes
* **[seaweedfs] Fix migration to v3.99**: Fixed migration issues when upgrading SeaweedFS to version 3.99, ensuring smooth upgrades ([**@kvaps**](https://github.com/kvaps) in #1572, #1575).
* **[nats] Merge container spec, not podTemplate**: Fixed NATS configuration to properly merge container specifications instead of podTemplate, ensuring correct container configuration ([**@lllamnyp**](https://github.com/lllamnyp) in #1571, #1574).
## Development, Testing, and CI/CD
* **[e2e] Increase Kubernetes connection timeouts**: Increased connection and request timeouts in E2E tests when communicating with Kubernetes API, improving test stability under high load and slow cluster response conditions ([**@IvanHunters**](https://github.com/IvanHunters) in #1570, #1573).
## Documentation
* **[website] Optimize website for mobile devices**: Improved website layout and responsiveness for mobile devices ([**@kvaps**](https://github.com/kvaps) in cozystack/website@3ab2338).
* **[website] Add OpenAPI UI**: Added OpenAPI UI documentation and integration ([**@kvaps**](https://github.com/kvaps) in cozystack/website@b1c1668).
* **[website] Update Cozystack video in hero banner**: Updated hero banner with new Cozystack video ([**@kvaps**](https://github.com/kvaps) in cozystack/website@e351137).
* **[website] Add screenshots carousel**: Added screenshots carousel to showcase Cozystack features ([**@kvaps**](https://github.com/kvaps) in cozystack/website@8422bd0).
---
**Full Changelog**: [v0.37.3...v0.37.4](https://github.com/cozystack/cozystack/compare/v0.37.3...v0.37.4)

View File

@@ -1,28 +0,0 @@
<!--
https://github.com/cozystack/cozystack/releases/tag/v0.37.5
-->
## Features and Improvements
* **[dashboard-controller] Move badges generation logic to internal dashboard component**: Moved badges generation logic to internal dashboard component for better code organization and maintainability ([**@kvaps**](https://github.com/kvaps) in #1567).
## Security
* **[redis] Bump Redis image version for security fixes**: Updated Redis image version to include latest security fixes, improving cluster security ([**@IvanHunters**](https://github.com/IvanHunters) in #1580).
* **[flux] Close Flux Operator ports to external access**: Removed hostPort and hostNetwork from Flux Operator Deployment, ensuring ports 8080 and 8081 are only accessible within the cluster, preventing external exposure and improving security ([**@IvanHunters**](https://github.com/IvanHunters) in #1581).
* **[ingress] Enforce HTTPS-only for API**: Added force-ssl-redirect annotation to default API Ingress, ensuring all HTTP traffic is redirected to HTTPS, preventing unencrypted external access and improving security ([**@IvanHunters**](https://github.com/IvanHunters) in #1582, #1585).
## Fixes
* **[nats] Fixes for NATS App Helm chart, fix template issues with config.merge**: Fixed template issues in NATS Helm chart related to config.merge value, ensuring correct configuration ([**@insignia96**](https://github.com/insignia96) in #1583, #1591).
* **[kubevirt] Fix: kubevirt metrics rule**: Fixed KubeVirt metrics rule configuration ([**@kvaps**](https://github.com/kvaps) in #1584, #1588).
## System Configuration
* **[core] rm talos lldp extension**: Removed Talos LLDP extension from core configuration ([**@nbykov0**](https://github.com/nbykov0) in #1586).
---
**Full Changelog**: [v0.37.4...v0.37.5](https://github.com/cozystack/cozystack/compare/v0.37.4...v0.37.5)

View File

@@ -1,30 +0,0 @@
<!--
https://github.com/cozystack/cozystack/releases/tag/v0.37.6
-->
## Features and Improvements
* **[api] Use shared informer cache**: Optimized API server by using shared informer cache, reducing API server load and improving performance ([**@lllamnyp**](https://github.com/lllamnyp) in #1539).
* **[dashboard] sync with upstream & enhancements**: Synchronized dashboard with upstream and added various enhancements ([**@kvaps**](https://github.com/kvaps) in #1603).
* **[cozystack-api][dashboard] Fix filtering for application services/ingresses/secrets**: Fixed filtering functionality for application services, ingresses, and secrets in both API and dashboard ([**@kvaps**](https://github.com/kvaps) in #1612).
## Fixes
* **[controller] Remove crdmem, handle DaemonSet**: Removed crdmem and improved DaemonSet handling in controller ([**@lllamnyp**](https://github.com/lllamnyp) in #1555).
* **[dashboard] Revert reconciler removal**: Reverted reconciler removal to restore proper dashboard functionality ([**@lllamnyp**](https://github.com/lllamnyp) in #1559).
* **[dashboard-controller] Fix static resources reconciliation and showing secrets**: Fixed static resources reconciliation and improved secret display in dashboard controller ([**@kvaps**](https://github.com/kvaps) in #1605).
* **[api,lineage] Ensure node-local traffic**: Ensured node-local traffic handling for API and lineage components ([**@lllamnyp**](https://github.com/lllamnyp) in #1606).
* **[virtual-machine] Revert per-vm network policies**: Reverted per-VM network policies to previous behavior ([**@lllamnyp**](https://github.com/lllamnyp) in #1611).
* **[cozy-lib] Fix: handling resources=nil**: Fixed handling of nil resources in cozy-lib templates ([**@kvaps**](https://github.com/kvaps) in #1607).
* **[nats] Use dig function to check for existing secret and prevent nil indexing**: Fixed NATS app chart to use dig function for checking existing secrets and prevent nil indexing errors ([**@kvaps**](https://github.com/kvaps) in #1609, #1610).
## Development, Testing, and CI/CD
* **[cozystack-controller] improve API tests**: Improved API tests for cozystack-controller ([**@lllamnyp**](https://github.com/lllamnyp) in #1599).
* **[kubernetes] Helm hooks for cleanup**: Added Helm hooks for cleanup operations in Kubernetes app ([**@lllamnyp**](https://github.com/lllamnyp) in #1616).
---
**Full Changelog**: [v0.37.5...v0.37.6](https://github.com/cozystack/cozystack/compare/v0.37.5...v0.37.6)

View File

@@ -1,18 +0,0 @@
<!--
https://github.com/cozystack/cozystack/releases/tag/v0.37.7
-->
## Fixes
* **[kubernetes] Cleanup loadbalancer services**: Added cleanup functionality for load balancer services in Kubernetes app ([**@lllamnyp**](https://github.com/lllamnyp) in #1622).
* **[rbac] Fix permissions for high-privilege users**: Fixed RBAC permissions for high-privilege users, ensuring proper access control ([**@lllamnyp**](https://github.com/lllamnyp) in #1624).
## System Configuration
* **[system] kubeovn: increase limits**: Increased resource limits for Kube-OVN components to improve stability and performance ([**@nbykov0**](https://github.com/nbykov0) in #1629).
---
**Full Changelog**: [v0.37.6...v0.37.7](https://github.com/cozystack/cozystack/compare/v0.37.6...v0.37.7)

View File

@@ -1,19 +0,0 @@
<!--
https://github.com/cozystack/cozystack/releases/tag/v0.37.8
-->
## Fixes
* **[cozy-lib] Fix malformed ResourceQuota rendering for LoadBalancer services**: Fixed malformed ResourceQuota rendering for LoadBalancer services in cozy-lib templates ([**@IvanHunters**](https://github.com/IvanHunters) in #1642).
* **[extra] ingress: rm spaces from external ip list**: Removed spaces from external IP list in ingress configuration, fixing formatting issues ([**@nbykov0**](https://github.com/nbykov0) in #1652).
* **scripts: fix 20 migration**: Fixed migration script #20 to ensure proper execution during upgrades ([**@nbykov0**](https://github.com/nbykov0) in #1653).
## System Configuration
* **Increase strimzi memory limit**: Increased memory limit for Strimzi Kafka operator to improve stability and performance ([**@nbykov0**](https://github.com/nbykov0) in #1651).
---
**Full Changelog**: [v0.37.7...v0.37.8](https://github.com/cozystack/cozystack/compare/v0.37.7...v0.37.8)

View File

@@ -1,19 +0,0 @@
<!--
https://github.com/cozystack/cozystack/releases/tag/v0.37.9
-->
## Improvements
* **[seaweedfs] Extended CA certificate duration to reduce disruptive CA rotations**: Extended CA certificate duration to reduce disruptive CA rotations. ([**@IvanHunters**](https://github.com/IvanHunters) in #1657, #1666).
* **[dashboard] Add config hash annotations to restart pods on config changes**: Added config hash annotations to restart pods when configuration changes, ensuring pods are automatically restarted when their configuration is updated ([**@kvaps**](https://github.com/kvaps) in #1662, #1665).
## Fixes
* **[tenant][kubernetes] Introduce better cleanup logic**: Improved cleanup logic for tenant Kubernetes resources, ensuring proper resource cleanup when tenants are deleted or updated ([**@kvaps**](https://github.com/kvaps) in #1661).
* **[dashboard] Fix loading arrays in forms when editing existing objects**: Fixed issue where arrays in forms were not loading correctly when editing existing objects in the dashboard ([**@kvaps**](https://github.com/kvaps)).
---
**Full Changelog**: [v0.37.8...v0.37.9](https://github.com/cozystack/cozystack/compare/v0.37.8...v0.37.9)

View File

@@ -1,235 +0,0 @@
# Cozystack v0.38 — "VPC & Enhanced Networking"
This release introduces **Virtual Private Cloud (VPC)** support, enabling advanced networking capabilities for tenant applications. We've also added VNC console support in the dashboard, made Kubernetes worker versions configurable, and delivered numerous improvements and fixes across the platform.
### Virtual Private Cloud (VPC) Networking
Cozystack v0.38.0 introduces Virtual Private Cloud (VPC) support, enabling platform administrators to create isolated network segments for tenant applications. VPCs provide network isolation and allow fine-grained control over network topology, subnets, and routing. Each VPC can contain multiple subnets, and administrators can configure subnet details including IP ranges, gateway settings, and DNS configuration.
The VPC feature integrates seamlessly with the Cozystack dashboard, allowing users to view and manage VPCs and their subnets through an intuitive interface. Subnet details are exposed in the dashboard as tables, making it easy to understand network configuration at a glance. VPC configuration is stored in ConfigMaps with predictable naming, ensuring reliable access to subnet information.
This feature is particularly valuable for multi-tenant environments where network isolation is critical, and for applications that require specific network configurations or routing rules.
### VNC Console for Virtual Machines
The Cozystack dashboard now includes a built-in VNC console for virtual machines, enabling users to access VM console directly from the web interface without requiring external tools. This feature provides immediate access to virtual machine consoles for troubleshooting, configuration, and maintenance tasks. The VNC console integration streamlines VM management workflows and improves the user experience by keeping all VM operations within the Cozystack dashboard.
## Highlights
* **Virtual Private Cloud (VPC)**: New VPC system module enables advanced networking with Multus CNI, subnet management, and network isolation for tenant applications ([**@nbykov0**](https://github.com/nbykov0) in #1543; [**@lllamnyp**](https://github.com/lllamnyp) in #1587, #1590, #1600, #1621, #1638).
* **VNC Console in Dashboard**: Users can now access virtual machine consoles directly from the dashboard, improving VM management experience ([**@kvaps**](https://github.com/kvaps) in #1627).
* **Configurable Kubernetes Worker Versions**: Platform administrators can now configure Kubernetes worker node versions independently, providing more flexibility in cluster management ([**@lllamnyp**](https://github.com/lllamnyp) in #1619).
* **Security Enhancements**: Multiple security improvements including HTTPS-only enforcement for API, closed Flux Operator ports, and Redis security updates ([**@IvanHunters**](https://github.com/IvanHunters) in #1580, #1581, #1582).
* **Cozy-lib Improvements**: Enhanced flatten function with better ResourceQuota handling and nil resource support ([**@lllamnyp**](https://github.com/lllamnyp) in #1647; [**@IvanHunters**](https://github.com/IvanHunters) in #1642; [**@kvaps**](https://github.com/kvaps) in #1607).
---
## New features
### VPC (Virtual Private Cloud)
* **[system] Add VPC**: Introduced Virtual Private Cloud system module with Multus CNI integration, enabling advanced networking capabilities for tenant applications ([**@nbykov0**](https://github.com/nbykov0) in #1543).
* **[vpc] Install Multus by default**: Multus CNI is now installed by default when VPC is enabled, providing multi-network interface support ([**@lllamnyp**](https://github.com/lllamnyp) in #1587).
* **[vpc] Give predictable name to subnet configmap**: Subnet configuration maps now use predictable naming for better management and debugging ([**@lllamnyp**](https://github.com/lllamnyp) in #1590).
* **[vpc] Entry per subnet in the subnets configmap**: Each subnet now has its own entry in the subnets configmap, improving subnet organization and management ([**@lllamnyp**](https://github.com/lllamnyp) in #1600).
* **[vpc,dashboard] Print subnet details as table**: Subnet details are now displayed as a table in the dashboard, improving visibility and management ([**@lllamnyp**](https://github.com/lllamnyp) in #1621).
* **[apps] Add VPC app**: Added VPC application for tenant use, enabling users to create and manage VPCs ([**@nbykov0**](https://github.com/nbykov0) in #1543).
### Dashboard
* **[dashboard] Introduce VNC console**: Added VNC console support in the dashboard, allowing users to access virtual machine consoles directly from the web interface ([**@kvaps**](https://github.com/kvaps) in #1627).
* **[dashboard] sync with upstream & enhancements**: Synchronized dashboard with upstream project and added various enhancements ([**@kvaps**](https://github.com/kvaps) in #1603).
* **[dashboard] Migrate patches to upstream project**: Migrated dashboard patches to upstream project for better maintainability ([**@kvaps**](https://github.com/kvaps) in #1569).
### Kubernetes
* **[kubernetes] Make worker version configurable**: Platform administrators can now configure Kubernetes worker node versions independently from control plane versions, providing more flexibility ([**@lllamnyp**](https://github.com/lllamnyp) in #1619).
* **[kubernetes] Use controlPlane.replicas field**: Fixed managed Kubernetes app to properly use the `controlPlane.replicas` field instead of hardcoding the value ([**@lllamnyp**](https://github.com/lllamnyp) in #1556).
* **[kubernetes] Helm hooks for cleanup**: Added Helm hooks for cleanup operations in Kubernetes app ([**@lllamnyp**](https://github.com/lllamnyp) in #1606).
### API & Platform
* **[api] Efficient listing of TenantNamespaces**: Optimized TenantNamespace listing by replacing per-namespace SubjectAccessReview calls with group-based rolebinding checks, significantly reducing API latency ([**@lllamnyp**](https://github.com/lllamnyp) in #1507).
* **[api] Use shared informer cache**: Optimized API server by using shared informer cache, reducing API server load and improving performance ([**@lllamnyp**](https://github.com/lllamnyp) in #1539).
* **[api] Fix representation of dynamic list kinds**: Fixed API representation of dynamic list kinds for better compatibility ([**@lllamnyp**](https://github.com/lllamnyp) in #1630).
* **[api] Delete previous instance when changing type**: API now properly deletes previous instance when changing application type ([**@lllamnyp**](https://github.com/lllamnyp) in #1579).
### Applications
* **[tenant] Allow listing workloads**: Enabled listing of workloads for tenants, improving visibility and management of tenant resources ([**@kvaps**](https://github.com/kvaps) in #1576).
* **[apps] Make VM service user facing**: Virtual machine services are now marked as user-facing, improving service discovery and visibility in the dashboard ([**@lllamnyp**](https://github.com/lllamnyp) in #1523).
* **[foundationdb] Upgrade FDB app for latest Cozy**: Upgraded FoundationDB application for compatibility with latest Cozystack version ([**@lllamnyp**](https://github.com/lllamnyp) in #1505).
### Storage & Backups
* **[seaweedfs] Update SeaweedFS v3.99 and deploy S3 as stacked service**: Updated SeaweedFS to version 3.99 and deployed S3 gateway as a stacked service for better integration and performance ([**@kvaps**](https://github.com/kvaps) in #1562).
* **[seaweedfs] Allow users to discover their buckets**: Users can now discover and list their S3 buckets in SeaweedFS, improving usability and bucket management ([**@kvaps**](https://github.com/kvaps) in #1528).
* **[velero] Set defaultItemOperationTimeout=24h**: Set default item operation timeout to 24 hours for Velero backups, preventing timeouts on large backup operations ([**@kvaps**](https://github.com/kvaps) in #1542).
### Monitoring & Operations
* **[monitoring] add settings alert for slack**: Added Slack integration configuration for Alerta alerts, enabling notifications to Slack channels ([**@scooby87**](https://github.com/scooby87) in #1545).
---
## Improvements (minor)
* **[lineage] Separate webhook from cozy controller**: Separated the lineage-controller-webhook from cozystack-controller into a separate daemonset component deployed on all control-plane nodes, reducing API server latency ([**@lllamnyp**](https://github.com/lllamnyp) in #1515).
* **[dashboard] Show service LB IP**: Fixed JSON path issue to correctly display Service LoadBalancer IPs in the dashboard table view ([**@lllamnyp**](https://github.com/lllamnyp) in #1524).
* **[dashboard] Update openapi-ui v1.0.3 + fixes**: Updated OpenAPI UI to version 1.0.3 with various fixes and improvements ([**@kvaps**](https://github.com/kvaps) in #1564).
* **[dashboard-controller] Move badges generation logic to internal dashboard component**: Moved badges generation logic to internal dashboard component for better code organization ([**@kvaps**](https://github.com/kvaps) in #1567).
* **[bucket] Expose bucket name in secrets**: Bucket names are now exposed in secrets for better integration with applications ([**@lllamnyp**](https://github.com/lllamnyp) in #1518).
* **[platform] Better migration for 0.36.2->0.37.2+**: Improved migration script for users upgrading directly from 0.36.2 to 0.37.2+ ([**@lllamnyp**](https://github.com/lllamnyp) in #1521).
* **[cozy-lib] Improve flatten function**: Improved flatten function in cozy-lib with better handling of complex resource structures ([**@lllamnyp**](https://github.com/lllamnyp) in #1647).
* **[dx] JSDoc compatible syntax for values.yaml**: Added JSDoc compatible syntax for values.yaml documentation ([**@kvaps**](https://github.com/kvaps) in #1536).
* **[system] Tune kubevirt rollout and eviction settings**: Tuned KubeVirt rollout and eviction settings for better stability ([**@nbykov0**](https://github.com/nbykov0) in #1544).
* **[system] multus: update to the latest version**: Updated Multus CNI to the latest version ([**@nbykov0**](https://github.com/nbykov0) in #1628).
* **[system] kubeovn: increase limits**: Increased resource limits for Kube-OVN components to improve stability and performance ([**@nbykov0**](https://github.com/nbykov0) in #1629).
* **[linstor] Update Piraeus Operator to v2.10.1 to enable RWX support**: Updated Piraeus Operator to v2.10.1, enabling ReadWriteMany (RWX) volume support ([**@kvaps**](https://github.com/kvaps) in #1650).
* **[ci,dx] Bump MariaDB operator version**: Bumped MariaDB operator version for latest features and bug fixes ([**@IvanHunters**](https://github.com/IvanHunters) in #1646).
---
## Bug fixes
* **[api] Fix RBAC for listing of TenantNamespaces and handle system:masters**: Fixed regression in TenantNamespace listing RBAC and added proper handling for system:masters group ([**@kvaps**](https://github.com/kvaps) in #1511).
* **[api] Fix listing tenantnamespaces for non-oidc users**: Fixed TenantNamespace listing functionality for users not using OIDC authentication ([**@kvaps**](https://github.com/kvaps) in #1517).
* **[dashboard] Fix logout**: Fixed dashboard logout functionality to properly clear session and redirect users ([**@kvaps**](https://github.com/kvaps) in #1510).
* **[installer] Add additional check to wait for lineage-webhook**: Added additional readiness check to ensure lineage-webhook is fully ready before proceeding with installation ([**@kvaps**](https://github.com/kvaps) in #1506).
* **[lineage] Check for nil chart in HelmRelease**: Added nil check to prevent crashes when lineage webhook encounters HelmReleases using `chartRef` instead of `chart` ([**@lllamnyp**](https://github.com/lllamnyp) in #1525).
* **[kamaji] Respect 3rd party labels**: Applied patch to Kamaji controller to respect third-party labels, preventing reconciliation loops ([**@lllamnyp**](https://github.com/lllamnyp) in #1531).
* **[redis-operator] Build patched operator in-tree**: Moved Redis operator build into Cozystack organization and patched it to prevent overwriting third-party labels ([**@lllamnyp**](https://github.com/lllamnyp) in #1547).
* **[mariadb-operator] Add post-delete job to remove PVCs**: Added post-delete job to automatically remove PersistentVolumeClaims when MariaDB instances are deleted ([**@IvanHunters**](https://github.com/IvanHunters) in #1553).
* **[seaweedfs] Fix migration to v3.99**: Fixed migration issues when upgrading SeaweedFS to version 3.99 ([**@kvaps**](https://github.com/kvaps) in #1572).
* **[nats] Merge container spec, not podTemplate**: Fixed NATS configuration to properly merge container specifications instead of podTemplate ([**@lllamnyp**](https://github.com/lllamnyp) in #1571).
* **[nats] Fixes for NATS App Helm chart, fix template issues with config.merge**: Fixed template issues in NATS Helm chart related to config.merge value ([**@insignia96**](https://github.com/insignia96) in #1583).
* **[nats] Fix NATS app chart to use existing secret credentials when present**: Fixed NATS app chart to use existing secret credentials when present, preventing credential regeneration ([**@insignia96**](https://github.com/insignia96) in #1599).
* **[kubevirt] Fix: kubevirt metrics rule**: Fixed KubeVirt metrics rule configuration ([**@kvaps**](https://github.com/kvaps) in #1584).
* **[controller] Remove crdmem, handle DaemonSet**: Removed crdmem and improved DaemonSet handling in controller ([**@lllamnyp**](https://github.com/lllamnyp) in #1555).
* **[dashboard] Revert reconciler removal**: Reverted reconciler removal to restore proper dashboard functionality ([**@lllamnyp**](https://github.com/lllamnyp) in #1559).
* **[dashboard-controller] Fix static resources reconciliation and showing secrets**: Fixed static resources reconciliation and improved secret display in dashboard controller ([**@kvaps**](https://github.com/kvaps) in #1615).
* **[cozystack-api][dashboard] Fix filtering for application services/ingresses/secrets**: Fixed filtering functionality for application services, ingresses, and secrets in both API and dashboard ([**@kvaps**](https://github.com/kvaps) in #1612).
* **[virtual-machine] Revert per-vm network policies**: Reverted per-VM network policies to previous behavior ([**@kvaps**](https://github.com/kvaps) in #1611).
* **[cozy-lib] Fix: handling resources=nil**: Fixed handling of nil resources in cozy-lib templates ([**@kvaps**](https://github.com/kvaps) in #1607).
* **[cozy-lib] Fix malformed ResourceQuota rendering for LoadBalancer services**: Fixed malformed ResourceQuota rendering for LoadBalancer services in cozy-lib templates ([**@IvanHunters**](https://github.com/IvanHunters) in #1642).
* **[kubernetes] Cleanup loadbalancer services**: Added cleanup functionality for load balancer services in Kubernetes app ([**@lllamnyp**](https://github.com/lllamnyp) in #1631).
* **[rbac] Fix permissions for high-privilege users**: Fixed RBAC permissions for high-privilege users, ensuring proper access control ([**@lllamnyp**](https://github.com/lllamnyp) in #1622).
* **[vpc] Fix access to subnet details configmap**: Fixed access to subnet details configmap in VPC functionality ([**@lllamnyp**](https://github.com/lllamnyp) in #1638).
* **[api,lineage] Ensure node-local traffic**: Ensured node-local traffic handling for API and lineage components ([**@lllamnyp**](https://github.com/lllamnyp) in #1554).
* **[extra] ingress: rm spaces from external ip list**: Removed spaces from external IP list in ingress configuration, fixing formatting issues ([**@nbykov0**](https://github.com/nbykov0) in #1652).
* **scripts: fix 20 migration**: Fixed migration script #20 to ensure proper execution during upgrades ([**@nbykov0**](https://github.com/nbykov0) in #1653).
---
## Security
* **[redis] Bump Redis image version for security fixes**: Updated Redis image version to include latest security fixes, improving cluster security ([**@IvanHunters**](https://github.com/IvanHunters) in #1580).
* **[flux] Close Flux Operator ports to external access**: Removed hostPort and hostNetwork from Flux Operator Deployment, ensuring ports 8080 and 8081 are only accessible within the cluster ([**@IvanHunters**](https://github.com/IvanHunters) in #1581).
* **[ingress] Enforce HTTPS-only for API**: Added force-ssl-redirect annotation to default API Ingress, ensuring all HTTP traffic is redirected to HTTPS ([**@IvanHunters**](https://github.com/IvanHunters) in #1582).
---
## Dependencies & version updates
* **Update LINSTOR v1.32.3**: Updated LINSTOR to version 1.32.3 with latest features and bug fixes ([**@kvaps**](https://github.com/kvaps) in #1565).
* **Update Talos Linux v1.11.3**: Updated Talos Linux to version 1.11.3 ([**@kvaps**](https://github.com/kvaps) in #1527).
* **Update Kube-OVN v1.14.11**: Updated Kube-OVN to version 1.14.11 ([**@kvaps**](https://github.com/kvaps) in #1514).
* **[linstor] Update Piraeus Operator to v2.10.1**: Updated Piraeus Operator to v2.10.1 to enable RWX support ([**@kvaps**](https://github.com/kvaps) in #1650).
* **[system] multus: update to the latest version**: Updated Multus CNI to the latest version ([**@nbykov0**](https://github.com/nbykov0) in #1628).
* **[ci,dx] Bump MariaDB operator version**: Bumped MariaDB operator version ([**@IvanHunters**](https://github.com/IvanHunters) in #1646).
* **Increase strimzi memory limit**: Increased memory limit for Strimzi Kafka operator to improve stability and performance ([**@nbykov0**](https://github.com/nbykov0) in #1651).
---
## System Configuration
* **[system] kube-ovn: turn off enableLb**: Disabled load balancer functionality in Kube-OVN configuration ([**@nbykov0**](https://github.com/nbykov0) in #1548).
* **[core] rm talos lldp extension**: Removed Talos LLDP extension from core configuration ([**@nbykov0**](https://github.com/nbykov0) in #1586).
---
## Development, Testing, and CI/CD
* **[tests] Make Kubernetes tests POSIX-compatible**: Replaced bash-specific constructs with POSIX-compliant code, ensuring tests work reliably with /bin/sh ([**@IvanHunters**](https://github.com/IvanHunters) in #1509).
* **[ferretdb] fix tests**: Fixed FerretDB tests to ensure proper execution ([**@IvanHunters**](https://github.com/IvanHunters) in #1540).
* **[e2e] Increase Kubernetes connection timeouts**: Increased connection and request timeouts in E2E tests when communicating with Kubernetes API ([**@IvanHunters**](https://github.com/IvanHunters) in #1570).
* **[cozystack-controller] improve API tests**: Improved API tests for cozystack-controller ([**@kvaps**](https://github.com/kvaps) in #1617).
* **[ci] Fix build from external forks**: Fixed build process to work correctly from external forks ([**@kvaps**](https://github.com/kvaps) in #1530).
* **[ci,dx] Add unit tests for cozy-lib**: Added unit tests for cozy-lib to improve code quality and reliability ([**@lllamnyp**](https://github.com/lllamnyp) in #1643).
---
## Documentation
* **[website] Add VPC page**: Added VPC documentation page explaining VPC features and usage ([**@nbykov0**](https://github.com/nbykov0) in cozystack/website@9ccac78).
* **[website] Add VPC to auto-update list**: Added VPC to auto-update list in documentation ([**@nbykov0**](https://github.com/nbykov0) in cozystack/website@ca2bce6).
* **[website] Update dashboard part in OIDC configuration doc**: Updated OIDC configuration documentation with dashboard information ([**@nbykov0**](https://github.com/nbykov0) in cozystack/website@6c44b93).
* **[website] Update storage requirements**: Updated storage requirements documentation ([**@nbykov0**](https://github.com/nbykov0) in cozystack/website@cac3af6).
* **[website] Add System Resource Planning Recommendations**: Added system resource planning recommendations documentation ([**@kvaps**](https://github.com/kvaps) in cozystack/website@c877c2a).
* **[website] Optimize website for mobile devices**: Improved website layout and responsiveness for mobile devices ([**@kvaps**](https://github.com/kvaps) in cozystack/website@3ab2338).
* **[website] Add OpenAPI UI**: Added OpenAPI UI documentation and integration ([**@kvaps**](https://github.com/kvaps) in cozystack/website@b1c1668).
* **[website] Update Cozystack video in hero banner**: Updated hero banner with new Cozystack video ([**@kvaps**](https://github.com/kvaps) in cozystack/website@e351137).
* **[website] Add screenshots carousel**: Added screenshots carousel to showcase Cozystack features ([**@kvaps**](https://github.com/kvaps) in cozystack/website@8422bd0).
* **[website] Update LINSTOR documentation**: Updated LINSTOR guide and set failmode=continue for ZFS configurations ([**@kvaps**](https://github.com/kvaps) in cozystack/website@033804e).
* **[website] Update managed apps reference**: Updated managed applications reference documentation ([**@kvaps**](https://github.com/kvaps) in cozystack/website@b886a74, cozystack/website@41c1849, cozystack/website@0ab71fd).
* **[website] Update external apps documentation**: Updated documentation for external applications ([**@kvaps**](https://github.com/kvaps) in cozystack/website@565dad9).
* **[website] Add naming conventions**: Added naming conventions documentation ([**@kvaps**](https://github.com/kvaps) in cozystack/website@b227abb).
* **[website] Update golden image documentation**: Updated documentation for creating golden images for virtual machines ([**@kvaps**](https://github.com/kvaps) in cozystack/website@34c2f3a, cozystack/website@ef65593).
* **[website] Fix documentation formatting**: Fixed alerts, infoboxes, tabs styles and main page formatting ([**@kvaps**](https://github.com/kvaps) in cozystack/website@e992e97, cozystack/website@b2c4dee).
* **[website] Fix typo in blog article**: Fixed typo in blog article ([**@kvaps**](https://github.com/kvaps) in cozystack/website@0a4bbf3).
* **[apps] vpc: more docs**: Added more VPC documentation ([**@nbykov0**](https://github.com/nbykov0) in #1594).
* **[apps] vpc: fix typo in README**: Fixed typo in VPC README ([**@nbykov0**](https://github.com/nbykov0) in #1637).
---
## Additional Repositories
### boot-to-talos
* **[boot-to-talos] Introduce boot/install mode**: Introduced boot/install mode in boot-to-talos tool ([**@kvaps**](https://github.com/kvaps) in cozystack/boot-to-talos#5).
### cozypkg
* **[cozypkg] Handle valuesFiles from cozypkg.cozystack.io/values-files annotation**: Added support for handling valuesFiles from annotation in cozypkg ([**@kvaps**](https://github.com/kvaps) in cozystack/cozypkg#8).
---
## Refactors & chores
* **[dashboard] Migrate patches to upstream project**: Migrated dashboard patches to upstream project for better maintainability ([**@kvaps**](https://github.com/kvaps) in #1569).
* **Update CODEOWNERS**: Updated CODEOWNERS file ([**@nbykov0**](https://github.com/nbykov0) in #1537).
* **Add QOSI to ADOPTERS.md**: Added QOSI to adopters list ([**@tabu-a**](https://github.com/tabu-a) in #1589).
---
## Breaking changes & upgrade notes
No breaking changes in this release.
---
## Contributors
We'd like to thank all contributors who made this release possible:
* [**@IvanHunters**](https://github.com/IvanHunters)
* [**@insignia96**](https://github.com/insignia96)
* [**@kvaps**](https://github.com/kvaps)
* [**@lllamnyp**](https://github.com/lllamnyp)
* [**@nbykov0**](https://github.com/nbykov0)
* [**@scooby87**](https://github.com/scooby87)
* [**@tabu-a**](https://github.com/tabu-a)
### New Contributors
We're excited to welcome our first-time contributors:
* [**@tabu-a**](https://github.com/tabu-a) - First contribution!
---
**Full Changelog**: [v0.37.0...v0.38.0](https://github.com/cozystack/cozystack/compare/v0.37.0...v0.38.0)
<!--
https://github.com/cozystack/cozystack/releases/tag/v0.38.0
-->

View File

@@ -1,19 +0,0 @@
<!--
https://github.com/cozystack/cozystack/releases/tag/v0.38.1
-->
## Improvements
* **[seaweedfs] Extended CA certificate duration to reduce disruptive CA rotations**: Extended CA certificate duration to reduce disruptive CA rotations. ([**@IvanHunters**](https://github.com/IvanHunters) in #1657, #1666).
* **[dashboard] Add config hash annotations to restart pods on config changes**: Added config hash annotations to restart pods when configuration changes, ensuring pods are automatically restarted when their configuration is updated ([**@kvaps**](https://github.com/kvaps) in #1662, #1665).
## Fixes
* **[tenant][kubernetes] Introduce better cleanup logic**: Improved cleanup logic for tenant Kubernetes resources, ensuring proper resource cleanup when tenants are deleted or updated ([**@kvaps**](https://github.com/kvaps) in #1661).
* **[dashboard] Fix loading arrays in forms when editing existing objects**: Fixed issue where arrays in forms were not loading correctly when editing existing objects in the dashboard ([**@kvaps**](https://github.com/kvaps)).
---
**Full Changelog**: [v0.38.0...v0.38.1](https://github.com/cozystack/cozystack/compare/v0.38.0...v0.38.1)

View File

@@ -1,13 +0,0 @@
<!--
https://github.com/cozystack/cozystack/releases/tag/v0.38.2
-->
## Fixes
* **[api] Revert dynamic list kinds representation fix (fixes namespace deletion regression)**: Reverted changes from #1630 that caused a regression affecting namespace deletion and upgrades from previous versions. The regression caused namespace deletion failures with errors like "content is not a list: []unstructured.Unstructured" during namespace finalization. This revert restores compatibility with namespace deletion controller and fixes upgrade issues from previous versions, particularly when running migration 20 ([**@kvaps**](https://github.com/kvaps) in #1677).
---
**Full Changelog**: [v0.38.1...v0.38.2](https://github.com/cozystack/cozystack/compare/v0.38.1...v0.38.2)

View File

@@ -1,14 +0,0 @@
<!--
https://github.com/cozystack/cozystack/releases/tag/v0.38.3
-->
## Improvements
* **[core:installer] Address buildx warnings for installer image builds**: Aligns Dockerfile syntax casing to remove buildx warnings, keeping installer builds clean ([**@nbykov0**](https://github.com/nbykov0) in #1682).
* **[system:coredns] Align CoreDNS app labels with Talos defaults**: Matches CoreDNS labels to Talos conventions so services select pods consistently across platform and tenant clusters ([**@nbykov0**](https://github.com/nbykov0) in #1675).
* **[system:monitoring-agents] Rename CoreDNS metrics service to avoid conflicts**: Renames the metrics service so it no longer clashes with the CoreDNS service used for name resolution in tenant clusters ([**@nbykov0**](https://github.com/nbykov0) in #1676).
---
**Full Changelog**: [v0.38.2...v0.38.3](https://github.com/cozystack/cozystack/compare/v0.38.2...v0.38.3)

View File

@@ -1,18 +0,0 @@
<!--
https://github.com/cozystack/cozystack/releases/tag/v0.38.4
-->
## Fixes
* **[linstor] Update piraeus-operator v2.10.2 to handle fsck checks reliably**: Upgrades LINSTOR CSI to avoid failed mounts when fsck sees mounted volumes, improving volume publish reliability ([**@kvaps**](https://github.com/kvaps) in #1689, #1697).
* **[dashboard] Nest CustomFormsOverride properties under spec.properties**: Fixes schema generation so custom form properties are placed under `spec.properties`, preventing mis-rendered or missing form fields ([**@kvaps**](https://github.com/kvaps) in #1692, #1700).
* **[virtual-machine] Guard PVC resize to only expand storage**: Ensures resize jobs run only when storage size increases, avoiding unintended shrink attempts during VM updates ([**@kvaps**](https://github.com/kvaps) in #1688, #1701).
## Documentation
* **[website] Clarify GPU check command**: Makes the kubectl command for validating GPU binding more explicit, including namespace context ([**@nbykov0**](https://github.com/nbykov0) in cozystack/website#379).
---
**Full Changelog**: [v0.38.3...v0.38.4](https://github.com/cozystack/cozystack/compare/v0.38.3...v0.38.4)

View File

@@ -1,95 +0,0 @@
# Cozystack v0.39 — "Enhanced Networking & Monitoring"
This release introduces topology-aware routing for Cilium services, automatic pod rollouts on configuration changes, improved monitoring capabilities, and numerous bug fixes and improvements across the platform.
## Highlights
* **Topology-Aware Routing**: Enabled topology-aware routing for Cilium services, improving traffic distribution and reducing latency by routing traffic to endpoints in the same zone when possible ([**@nbykov0**](https://github.com/nbykov0) in #1734).
* **Automatic Pod Rollouts**: Cilium and Cilium operator pods now automatically restart when configuration changes, ensuring configuration updates are applied immediately ([**@kvaps**](https://github.com/kvaps) in #1728).
* **Windows VM Scheduling**: Added nodeAffinity configuration for Windows VMs based on scheduling config, enabling dedicated nodes for Windows workloads ([**@kvaps**](https://github.com/kvaps) in #1693).
* **SeaweedFS Updates**: Updated to SeaweedFS v4.02 with improved S3 daemon performance and fixes ([**@kvaps**](https://github.com/kvaps) in #1725).
---
## Major Features and Improvements
### Networking
* **[system/cilium] Enable topology-aware routing for services**: Enabled topology-aware routing for services, improving traffic distribution and reducing latency by routing traffic to endpoints in the same zone when possible. This feature helps optimize network performance in multi-zone deployments ([**@nbykov0**](https://github.com/nbykov0) in #1734).
* **[cilium] Enable automatic pod rollout on configmap updates**: Cilium and Cilium operator pods now automatically restart when the cilium-config ConfigMap is updated, ensuring configuration changes are applied immediately without manual intervention ([**@kvaps**](https://github.com/kvaps) in #1728).
### Virtual Machines
* **[virtual-machine,vm-instance] Add nodeAffinity for Windows VMs based on scheduling config**: Added nodeAffinity configuration to virtual-machine and vm-instance charts to support dedicated nodes for Windows VMs. When `dedicatedNodesForWindowsVMs` is enabled in the `cozystack-scheduling` ConfigMap, Windows VMs are scheduled on nodes with label `scheduling.cozystack.io/vm-windows=true`, while non-Windows VMs prefer nodes without this label ([**@kvaps**](https://github.com/kvaps) in #1693).
### Storage
* **Update SeaweedFS v4.02**: Updated SeaweedFS to version 4.02 with improved performance for S3 daemon and fixes for known issues. This update includes better S3 compatibility and performance improvements ([**@kvaps**](https://github.com/kvaps) in #1725).
### Tools
* **[talm] feat(init)!: require --name flag for cluster name**: Breaking change: The `talm init` command now requires the `--name` flag to specify the cluster name. This ensures consistent cluster naming and prevents accidental initialization without a name ([**@lexfrei**](https://github.com/lexfrei) in cozystack/talm#86).
* **[talm] feat(template): preserve extra YAML documents in output**: Templates now preserve extra YAML documents in the output, allowing for more flexible template processing ([**@lexfrei**](https://github.com/lexfrei) in cozystack/talm#87).
* **[talm] feat: add directory expansion for -f flag**: Added directory expansion support for the `-f` flag, allowing users to specify directories instead of individual files ([**@kvaps**](https://github.com/kvaps) in cozystack/talm@ca5713e).
* **[talm] Introduce automatic root detection**: Added automatic root detection logic to simplify talm usage and reduce manual configuration ([**@kvaps**](https://github.com/kvaps) in cozystack/talm@d165162).
* **[talm] Introduce talm kubeconfig --login command**: Added new `talm kubeconfig --login` command for easier kubeconfig management ([**@kvaps**](https://github.com/kvaps) in cozystack/talm@5f7e05b).
* **[talm] Introduce encryption**: Added encryption support to talm for secure configuration management ([**@kvaps**](https://github.com/kvaps) in cozystack/talm#81).
* **[talm] Replace code-generation with wrapper on talosctl**: Refactored talm to use a wrapper on talosctl instead of code generation, simplifying the codebase and improving maintainability ([**@kvaps**](https://github.com/kvaps) in cozystack/talm#80).
* **[talm] Use go embed instead of code generation**: Migrated from code generation to go embed for better build performance and simpler dependency management ([**@kvaps**](https://github.com/kvaps) in cozystack/talm#79).
* **[boot-to-talos] Cozystack: Update Talos Linux v1.11.3**: Updated boot-to-talos to use Talos Linux v1.11.3 ([**@kvaps**](https://github.com/kvaps) in cozystack/boot-to-talos#7).
## Improvements
* **[seaweedfs] Extended CA certificate duration to reduce disruptive CA rotations**: Extended CA certificate duration to reduce disruptive CA rotations, improving long-term certificate management and reducing operational overhead ([**@IvanHunters**](https://github.com/IvanHunters) in #1657).
* **[dashboard] Add config hash annotations to restart pods on config changes**: Added config hash annotations to dashboard deployment templates to ensure pods are automatically restarted when their configuration changes, ensuring configuration updates are applied immediately ([**@kvaps**](https://github.com/kvaps) in #1662).
* **[tenant][kubernetes] Introduce better cleanup logic**: Improved cleanup logic for tenant Kubernetes resources, ensuring proper resource cleanup when tenants are deleted or updated. Added automated pre-delete cleanup job for tenant namespaces to remove tenant-related releases during uninstall ([**@kvaps**](https://github.com/kvaps) in #1661).
* **[system:coredns] update coredns app labels to match Talos coredns labels**: Updated coredns app labels to match Talos coredns labels, ensuring consistency across the platform ([**@nbykov0**](https://github.com/nbykov0) in #1675).
* **[system:monitoring-agents] rename coredns metrics service**: Renamed coredns metrics service to avoid interference with coredns service used for name resolution in tenant k8s clusters ([**@nbykov0**](https://github.com/nbykov0) in #1676).
* **[core:installer] Address buildx warnings**: Fixed Dockerfile syntax warnings from buildx, ensuring clean builds without warnings ([**@nbykov0**](https://github.com/nbykov0) in #1682).
* **[talm] Refactor root detection logic into single file**: Improved code organization by consolidating root detection logic into a single file ([**@kvaps**](https://github.com/kvaps) in cozystack/talm@487b479).
* **[talm] Refactor init logic, better upgrade**: Improved initialization logic and upgrade process for better reliability ([**@kvaps**](https://github.com/kvaps) in cozystack/talm@c512777).
* **[talm] Sugar for kubeconfig command**: Added convenience features to the kubeconfig command for improved usability ([**@kvaps**](https://github.com/kvaps) in cozystack/talm@a4010b3).
* **[talm] wrap upgrade command**: Wrapped upgrade command for better integration and error handling ([**@kvaps**](https://github.com/kvaps) in cozystack/talm@2e1afbf).
* **[talm] docs(readme): add Homebrew installation option**: Added Homebrew installation option to the README for easier installation on macOS ([**@lexfrei**](https://github.com/lexfrei) in cozystack/talm@12bd4f2).
* **[talm] cozystack: disable nodeCIDRs allocation**: Disabled nodeCIDRs allocation in talm for better network configuration control ([**@kvaps**](https://github.com/kvaps) in cozystack/talm#82).
* **[talm] Update license to Apache2.0**: Updated license to Apache 2.0 for better compatibility and clarity ([**@kvaps**](https://github.com/kvaps) in cozystack/talm@eda1032).
## Fixes
* **[apps] Refactor apiserver to use typed objects and fix UnstructuredList GVK**: Refactored the apiserver REST handlers to use typed objects (`appsv1alpha1.Application`) instead of `unstructured.Unstructured`, eliminating the need for runtime conversions and simplifying the codebase. Additionally, fixed an issue where `UnstructuredList` objects were using the first registered kind from `typeToGVK` instead of the kind from the object's field when multiple kinds are registered with the same Go type. This fix includes the upstream fix from kubernetes/kubernetes#135537 ([**@kvaps**](https://github.com/kvaps) in #1679).
* **[dashboard] Fix CustomFormsOverride schema to nest properties under spec.properties**: Fixed the logic for generating CustomFormsOverride schema to properly nest properties under `spec.properties` instead of directly under `properties`, ensuring correct form schema generation ([**@kvaps**](https://github.com/kvaps) in #1692).
* **[virtual-machine] Improve check for resizing job**: Improved storage resize logic to only expand persistent volume claims when storage is being increased, preventing unintended storage reduction operations. Added validation to accurately compare current and desired storage sizes before triggering resize operations ([**@kvaps**](https://github.com/kvaps) in #1688).
* **[linstor] Update piraeus-operator v2.10.2**: Updated LINSTOR CSI to fix issues with the new fsck behaviour, resolving mount failures when fsck attempts to run on mounted devices ([**@kvaps**](https://github.com/kvaps) in #1689).
* **[api] Revert dynamic list kinds representation fix (fixes namespace deletion regression)**: Reverted changes from #1630 that caused a regression affecting namespace deletion and upgrades from previous versions. The regression caused namespace deletion failures with errors like "content is not a list: []unstructured.Unstructured" during namespace finalization. This revert restores compatibility with namespace deletion controller and fixes upgrade issues from previous versions ([**@kvaps**](https://github.com/kvaps) in #1677).
* **[talm] fix: normalize template paths for Windows compatibility**: Fixed template path handling to ensure Windows compatibility by normalizing paths ([**@lexfrei**](https://github.com/lexfrei) in cozystack/talm#88).
## Dependencies
* **Update SeaweedFS v4.02**: Updated SeaweedFS to version 4.02 ([**@kvaps**](https://github.com/kvaps) in #1725).
* **[linstor] Update piraeus-operator v2.10.2**: Updated piraeus-operator to version 2.10.2 ([**@kvaps**](https://github.com/kvaps) in #1689).
* **[talm] Cozystack: Update Talos Linux v1.11.3**: Updated talm to use Talos Linux v1.11.3 ([**@kvaps**](https://github.com/kvaps) in cozystack/talm#83).
## Documentation
* **[website] Add article: Talm v0.17: Built-in Age Encryption for Secrets Management**: Added comprehensive blog post announcing Talm v0.17 and its built-in age-based encryption for secrets. Covers initial setup and key generation, encryption/decryption workflows, idempotent encryption behavior, automatic .gitignore handling, file permission safeguards, security best practices, and guidance for GitOps and CI/CD integration ([**@kvaps**](https://github.com/kvaps) in [cozystack/website#384](https://github.com/cozystack/website/pull/384)).
* **[website] docs(talm): update talm init syntax for mandatory --preset and --name flags**: Updated documentation to reflect breaking changes in talm, adding mandatory `--preset` and `--name` flags to the talm init command ([**@lexfrei**](https://github.com/lexfrei) in cozystack/website#386).
---
## Contributors
We'd like to thank all contributors who made this release possible:
* [**@IvanHunters**](https://github.com/IvanHunters)
* [**@kvaps**](https://github.com/kvaps)
* [**@lexfrei**](https://github.com/lexfrei)
* [**@nbykov0**](https://github.com/nbykov0)
---
**Full Changelog**: [v0.38.0...v0.39.0](https://github.com/cozystack/cozystack/compare/v0.38.0...v0.39.0)
<!--
https://github.com/cozystack/cozystack/releases/tag/v0.39.0
-->

View File

@@ -1,12 +0,0 @@
<!--
https://github.com/cozystack/cozystack/releases/tag/v0.39.1
-->
## Features and Improvements
* **[monitoring] Add SLACK_SEVERITY_FILTER field and VMAgent for tenant monitoring**: Introduced the SLACK_SEVERITY_FILTER environment variable in the Alerta deployment to enable filtering of alert severities for Slack notifications based on the disabledSeverity configuration. Additionally, added a VMAgent resource template for scraping metrics within tenant namespaces, improving monitoring granularity and control. This enhancement allows administrators to configure which alert severities are sent to Slack and enables tenant-specific metrics collection for better observability ([**@IvanHunters**](https://github.com/IvanHunters) in #1712).
---
**Full Changelog**: [v0.39.0...v0.39.1](https://github.com/cozystack/cozystack/compare/v0.39.0...v0.39.1)

148
go.mod
View File

@@ -2,37 +2,33 @@
module github.com/cozystack/cozystack
go 1.25.0
go 1.23.0
require (
github.com/fluxcd/helm-controller/api v1.4.3
github.com/go-logr/logr v1.4.3
github.com/go-logr/zapr v1.3.0
github.com/fluxcd/helm-controller/api v1.1.0
github.com/google/gofuzz v1.2.0
github.com/onsi/ginkgo/v2 v2.23.3
github.com/onsi/gomega v1.37.0
github.com/prometheus/client_golang v1.22.0
github.com/robfig/cron/v3 v3.0.1
github.com/spf13/cobra v1.9.1
go.uber.org/zap v1.27.0
github.com/onsi/ginkgo/v2 v2.19.0
github.com/onsi/gomega v1.33.1
github.com/spf13/cobra v1.8.1
github.com/stretchr/testify v1.9.0
gopkg.in/yaml.v2 v2.4.0
k8s.io/api v0.34.1
k8s.io/apiextensions-apiserver v0.34.1
k8s.io/apimachinery v0.34.1
k8s.io/apiserver v0.34.1
k8s.io/client-go v0.34.1
k8s.io/component-base v0.34.1
k8s.io/api v0.31.2
k8s.io/apiextensions-apiserver v0.31.2
k8s.io/apimachinery v0.31.2
k8s.io/apiserver v0.31.2
k8s.io/client-go v0.31.2
k8s.io/component-base v0.31.2
k8s.io/klog/v2 v2.130.1
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b
k8s.io/utils v0.0.0-20250820121507-0af2bda4dd1d
sigs.k8s.io/controller-runtime v0.22.2
sigs.k8s.io/structured-merge-diff/v4 v4.7.0
k8s.io/kube-openapi v0.0.0-20240827152857-f7e401e7b4c2
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8
sigs.k8s.io/controller-runtime v0.19.0
sigs.k8s.io/structured-merge-diff/v4 v4.4.1
)
require (
cel.dev/expr v0.24.0 // indirect
github.com/NYTimes/gziphandler v1.1.1 // indirect
github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/blang/semver/v4 v4.0.0 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
@@ -40,90 +36,86 @@ require (
github.com/coreos/go-semver v0.3.1 // indirect
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/emicklei/go-restful/v3 v3.12.2 // indirect
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
github.com/evanphx/json-patch v4.12.0+incompatible // indirect
github.com/evanphx/json-patch/v5 v5.9.11 // indirect
github.com/evanphx/json-patch/v5 v5.9.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fluxcd/pkg/apis/kustomize v1.13.0 // indirect
github.com/fluxcd/pkg/apis/meta v1.22.0 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
github.com/fluxcd/pkg/apis/kustomize v1.6.1 // indirect
github.com/fluxcd/pkg/apis/meta v1.6.1 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-logr/zapr v1.3.0 // indirect
github.com/go-openapi/jsonpointer v0.21.0 // indirect
github.com/go-openapi/jsonreference v0.21.0 // indirect
github.com/go-openapi/jsonreference v0.20.2 // indirect
github.com/go-openapi/swag v0.23.0 // indirect
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/btree v1.1.3 // indirect
github.com/google/cel-go v0.26.0 // indirect
github.com/google/gnostic-models v0.7.0 // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect
github.com/google/cel-go v0.21.0 // indirect
github.com/google/gnostic-models v0.6.8 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect
github.com/imdario/mergo v0.3.6 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/mailru/easyjson v0.9.0 // indirect
github.com/moby/spdystream v0.5.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/moby/spdystream v0.4.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_golang v1.19.1 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.62.0 // indirect
github.com/prometheus/common v0.55.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/spf13/pflag v1.0.7 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/stoewer/go-strcase v1.3.0 // indirect
github.com/x448/float16 v0.8.4 // indirect
go.etcd.io/etcd/api/v3 v3.6.4 // indirect
go.etcd.io/etcd/client/pkg/v3 v3.6.4 // indirect
go.etcd.io/etcd/client/v3 v3.6.4 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 // indirect
go.opentelemetry.io/otel v1.35.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0 // indirect
go.opentelemetry.io/otel/metric v1.35.0 // indirect
go.opentelemetry.io/otel/sdk v1.34.0 // indirect
go.opentelemetry.io/otel/trace v1.35.0 // indirect
go.opentelemetry.io/proto/otlp v1.5.0 // indirect
go.etcd.io/etcd/api/v3 v3.5.16 // indirect
go.etcd.io/etcd/client/pkg/v3 v3.5.16 // indirect
go.etcd.io/etcd/client/v3 v3.5.16 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect
go.opentelemetry.io/otel v1.28.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 // indirect
go.opentelemetry.io/otel/metric v1.28.0 // indirect
go.opentelemetry.io/otel/sdk v1.28.0 // indirect
go.opentelemetry.io/otel/trace v1.28.0 // indirect
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.yaml.in/yaml/v2 v2.4.2 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/crypto v0.42.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/crypto v0.31.0 // indirect
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
golang.org/x/net v0.45.0 // indirect
golang.org/x/oauth2 v0.29.0 // indirect
golang.org/x/sync v0.17.0 // indirect
golang.org/x/sys v0.36.0 // indirect
golang.org/x/term v0.35.0 // indirect
golang.org/x/text v0.29.0 // indirect
golang.org/x/time v0.11.0 // indirect
golang.org/x/tools v0.37.0 // indirect
golang.org/x/net v0.33.0 // indirect
golang.org/x/oauth2 v0.23.0 // indirect
golang.org/x/sync v0.10.0 // indirect
golang.org/x/sys v0.28.0 // indirect
golang.org/x/term v0.27.0 // indirect
golang.org/x/text v0.21.0 // indirect
golang.org/x/time v0.7.0 // indirect
golang.org/x/tools v0.26.0 // indirect
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb // indirect
google.golang.org/grpc v1.72.1 // indirect
google.golang.org/protobuf v1.36.5 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect
google.golang.org/grpc v1.65.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/kms v0.34.1 // indirect
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 // indirect
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect
sigs.k8s.io/randfill v1.0.0 // indirect
sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect
sigs.k8s.io/yaml v1.6.0 // indirect
k8s.io/kms v0.31.2 // indirect
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.0 // indirect
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
sigs.k8s.io/yaml v1.4.0 // indirect
)
// See: issues.k8s.io/135537
replace k8s.io/apimachinery => github.com/cozystack/apimachinery v0.0.0-20251219010959-1f91eabae46c

341
go.sum
View File

@@ -1,11 +1,11 @@
cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY=
cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw=
github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I=
github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI=
github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
@@ -18,44 +18,45 @@ github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/cozystack/apimachinery v0.0.0-20251219010959-1f91eabae46c h1:C2wIfH/OzhU9XOK/e6Ik9cg7nZ1z6fN4lf6a3yFdik8=
github.com/cozystack/apimachinery v0.0.0-20251219010959-1f91eabae46c/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU=
github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84=
github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU=
github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM=
github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg=
github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/fluxcd/helm-controller/api v1.4.3 h1:CdZwjL1liXmYCWyk2jscmFEB59tICIlnWB9PfDDW5q4=
github.com/fluxcd/helm-controller/api v1.4.3/go.mod h1:0XrBhKEaqvxyDj/FziG1Q8Fmx2UATdaqLgYqmZh6wW4=
github.com/fluxcd/pkg/apis/kustomize v1.13.0 h1:GGf0UBVRIku+gebY944icVeEIhyg1P/KE3IrhOyJJnE=
github.com/fluxcd/pkg/apis/kustomize v1.13.0/go.mod h1:TLKVqbtnzkhDuhWnAsN35977HvRfIjs+lgMuNro/LEc=
github.com/fluxcd/pkg/apis/meta v1.22.0 h1:EHWQH5ZWml7i8eZ/AMjm1jxid3j/PQ31p+hIwCt6crM=
github.com/fluxcd/pkg/apis/meta v1.22.0/go.mod h1:Kc1+bWe5p0doROzuV9XiTfV/oL3ddsemYXt8ZYWdVVg=
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
github.com/fluxcd/helm-controller/api v1.1.0 h1:NS5Wm3U6Kv4w7Cw2sDOV++vf2ecGfFV00x1+2Y3QcOY=
github.com/fluxcd/helm-controller/api v1.1.0/go.mod h1:BgHMgMY6CWynzl4KIbHpd6Wpn3FN9BqgkwmvoKCp6iE=
github.com/fluxcd/pkg/apis/kustomize v1.6.1 h1:22FJc69Mq4i8aCxnKPlddHhSMyI4UPkQkqiAdWFcqe0=
github.com/fluxcd/pkg/apis/kustomize v1.6.1/go.mod h1:5dvQ4IZwz0hMGmuj8tTWGtarsuxW0rWsxJOwC6i+0V8=
github.com/fluxcd/pkg/apis/meta v1.6.1 h1:maLhcRJ3P/70ArLCY/LF/YovkxXbX+6sTWZwZQBeNq0=
github.com/fluxcd/pkg/apis/meta v1.6.1/go.mod h1:YndB/gxgGZmKfqpAfFxyCDNFJFP0ikpeJzs66jwq280=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ=
github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg=
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
@@ -63,171 +64,162 @@ github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZ
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
github.com/google/cel-go v0.26.0 h1:DPGjXackMpJWH680oGY4lZhYjIameYmR+/6RBdDGmaI=
github.com/google/cel-go v0.26.0/go.mod h1:A9O8OU9rdvrK5MQyrqfIxo1a0u4g3sF8KB6PUIaryMM=
github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo=
github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ=
github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
github.com/google/cel-go v0.21.0 h1:cl6uW/gxN+Hy50tNYvI691+sXxioCnstFzLp2WO4GCI=
github.com/google/cel-go v0.21.0/go.mod h1:rHUlWCcBKgyEk+eV03RPdZUekPp6YcJwV0FxuUksYxc=
github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg=
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 h1:FKHo8hFI3A+7w0aUQuYXQ+6EN5stWmeY/AZqtM8xk9k=
github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo=
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA=
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 h1:qnpSQwGEnkcRpTqNOIR6bJbR0gAorgP9CSALpRcKoAA=
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1/go.mod h1:lXGCsh6c22WGtjr+qGHj1otzZpV/1kwTMAqkwZsnWRU=
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.0 h1:FbSCl+KggFl+Ocym490i/EyXF4lPgLoUtcSWquBM0Rs=
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.0/go.mod h1:qOchhhIlmRcqk/O9uCo/puJlyo07YINaIqdZfZG3Jkc=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw=
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI=
github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k=
github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28=
github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jonboulle/clockwork v0.5.0 h1:Hyh9A8u51kptdkR+cqRpT1EebBwTn1oK9YfGYbdFz6I=
github.com/jonboulle/clockwork v0.5.0/go.mod h1:3mZlmanh0g2NDKO5TWZVJAfofYk64M7XN3SzBPjZF60=
github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ=
github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
github.com/moby/spdystream v0.5.0 h1:7r0J1Si3QO/kjRitvSLVVFUjxMEb/YLj6S9FF62JBCU=
github.com/moby/spdystream v0.5.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/moby/spdystream v0.4.0 h1:Vy79D6mHeJJjiPdFEL2yku1kl0chZpJfZcPpb16BRl8=
github.com/moby/spdystream v0.4.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8=
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/onsi/ginkgo/v2 v2.23.3 h1:edHxnszytJ4lD9D5Jjc4tiDkPBZ3siDeJJkUZJJVkp0=
github.com/onsi/ginkgo/v2 v2.23.3/go.mod h1:zXTP6xIp3U8aVuXN8ENK9IXRaTjFnpVB9mGmaSRvxnM=
github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y=
github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0=
github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA=
github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To=
github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk=
github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js=
github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0=
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M=
github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs=
github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 h1:6fotK7otjonDflCTK0BCfls4SPy3NcCVb5dqqmbRknE=
github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75/go.mod h1:KO6IkyS8Y3j8OdNO85qEYBsRPuteD+YciPomcXdrMnk=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510 h1:S2dVYn90KE98chqDkyE9Z4N61UnQd+KOfgp5Iu53llk=
github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.etcd.io/bbolt v1.4.2 h1:IrUHp260R8c+zYx/Tm8QZr04CX+qWS5PGfPdevhdm1I=
go.etcd.io/bbolt v1.4.2/go.mod h1:Is8rSHO/b4f3XigBC0lL0+4FwAQv3HXEEIgFMuKHceM=
go.etcd.io/etcd/api/v3 v3.6.4 h1:7F6N7toCKcV72QmoUKa23yYLiiljMrT4xCeBL9BmXdo=
go.etcd.io/etcd/api/v3 v3.6.4/go.mod h1:eFhhvfR8Px1P6SEuLT600v+vrhdDTdcfMzmnxVXXSbk=
go.etcd.io/etcd/client/pkg/v3 v3.6.4 h1:9HBYrjppeOfFjBjaMTRxT3R7xT0GLK8EJMVC4xg6ok0=
go.etcd.io/etcd/client/pkg/v3 v3.6.4/go.mod h1:sbdzr2cl3HzVmxNw//PH7aLGVtY4QySjQFuaCgcRFAI=
go.etcd.io/etcd/client/v3 v3.6.4 h1:YOMrCfMhRzY8NgtzUsHl8hC2EBSnuqbR3dh84Uryl7A=
go.etcd.io/etcd/client/v3 v3.6.4/go.mod h1:jaNNHCyg2FdALyKWnd7hxZXZxZANb0+KGY+YQaEMISo=
go.etcd.io/etcd/pkg/v3 v3.6.4 h1:fy8bmXIec1Q35/jRZ0KOes8vuFxbvdN0aAFqmEfJZWA=
go.etcd.io/etcd/pkg/v3 v3.6.4/go.mod h1:kKcYWP8gHuBRcteyv6MXWSN0+bVMnfgqiHueIZnKMtE=
go.etcd.io/etcd/server/v3 v3.6.4 h1:LsCA7CzjVt+8WGrdsnh6RhC0XqCsLkBly3ve5rTxMAU=
go.etcd.io/etcd/server/v3 v3.6.4/go.mod h1:aYCL/h43yiONOv0QIR82kH/2xZ7m+IWYjzRmyQfnCAg=
go.etcd.io/raft/v3 v3.6.0 h1:5NtvbDVYpnfZWcIHgGRk9DyzkBIXOi8j+DDp1IcnUWQ=
go.etcd.io/raft/v3 v3.6.0/go.mod h1:nLvLevg6+xrVtHUmVaTcTz603gQPHfh7kUAwV6YpfGo=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 h1:x7wzEgXfnzJcHDwStJT+mxOz4etr2EcexjqhBvmoakw=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0/go.mod h1:rg+RlpR5dKwaS95IyyZqj5Wd4E13lk/msnTS0Xl9lJM=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 h1:yd02MEjBdJkG3uabWP9apV+OuWRIXGDuJEUJbOHmCFU=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0/go.mod h1:umTcuxiv1n/s/S6/c2AT/g2CQ7u5C59sHDNmfSwgz7Q=
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 h1:OeNbIYk/2C15ckl7glBlOBp5+WlYsOElzTNmiPW/x60=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0/go.mod h1:7Bept48yIeqxP2OZ9/AqIpYS94h2or0aB4FypJTc8ZM=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0 h1:tgJ0uaNS4c98WRNUEx5U3aDlrDOI5Rs+1Vifcw4DJ8U=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0/go.mod h1:U7HYyW0zt/a9x5J1Kjs+r1f/d4ZHnYFclhYY2+YbeoE=
go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A=
go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU=
go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk=
go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w=
go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4=
go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4=
go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI=
go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE=
go.etcd.io/etcd/api/v3 v3.5.16 h1:WvmyJVbjWqK4R1E+B12RRHz3bRGy9XVfh++MgbN+6n0=
go.etcd.io/etcd/api/v3 v3.5.16/go.mod h1:1P4SlIP/VwkDmGo3OlOD7faPeP8KDIFhqvciH5EfN28=
go.etcd.io/etcd/client/pkg/v3 v3.5.16 h1:ZgY48uH6UvB+/7R9Yf4x574uCO3jIx0TRDyetSfId3Q=
go.etcd.io/etcd/client/pkg/v3 v3.5.16/go.mod h1:V8acl8pcEK0Y2g19YlOV9m9ssUe6MgiDSobSoaBAM0E=
go.etcd.io/etcd/client/v2 v2.305.13 h1:RWfV1SX5jTU0lbCvpVQe3iPQeAHETWdOTb6pxhd77C8=
go.etcd.io/etcd/client/v2 v2.305.13/go.mod h1:iQnL7fepbiomdXMb3om1rHq96htNNGv2sJkEcZGDRRg=
go.etcd.io/etcd/client/v3 v3.5.16 h1:sSmVYOAHeC9doqi0gv7v86oY/BTld0SEFGaxsU9eRhE=
go.etcd.io/etcd/client/v3 v3.5.16/go.mod h1:X+rExSGkyqxvu276cr2OwPLBaeqFu1cIl4vmRjAD/50=
go.etcd.io/etcd/pkg/v3 v3.5.13 h1:st9bDWNsKkBNpP4PR1MvM/9NqUPfvYZx/YXegsYEH8M=
go.etcd.io/etcd/pkg/v3 v3.5.13/go.mod h1:N+4PLrp7agI/Viy+dUYpX7iRtSPvKq+w8Y14d1vX+m0=
go.etcd.io/etcd/raft/v3 v3.5.13 h1:7r/NKAOups1YnKcfro2RvGGo2PTuizF/xh26Z2CTAzA=
go.etcd.io/etcd/raft/v3 v3.5.13/go.mod h1:uUFibGLn2Ksm2URMxN1fICGhk8Wu96EfDQyuLhAcAmw=
go.etcd.io/etcd/server/v3 v3.5.13 h1:V6KG+yMfMSqWt+lGnhFpP5z5dRUj1BDRJ5k1fQ9DFok=
go.etcd.io/etcd/server/v3 v3.5.13/go.mod h1:K/8nbsGupHqmr5MkgaZpLlH1QdX1pcNQLAkODy44XcQ=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 h1:9G6E0TXzGFVfTnawRzrPl83iHOAV7L8NJiR8RSGYV1g=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg=
go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo=
go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 h1:qFffATk0X+HD+f1Z8lswGiOQYKHRlzfmdJm0wEaVrFA=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0/go.mod h1:MOiCmryaYtc+V0Ei+Tx9o5S1ZjA7kzLucuVuyzBZloQ=
go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q=
go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s=
go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE=
go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg=
go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g=
go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI=
go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0=
go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=
golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
@@ -236,48 +228,50 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM=
golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
golang.org/x/oauth2 v0.29.0 h1:WdYw2tdTK1S8olAzWHdgeqfy+Mtm9XNhv/xJsY65d98=
golang.org/x/oauth2 v0.29.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs=
golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ=
golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE=
golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w=
golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw=
gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb h1:p31xT4yrYrSM/G4Sn2+TNUkVhFCbG9y8itM2S6Th950=
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:jbe3Bkdp+Dh2IrslsFCklNhweNTBgSYanP1UXhJDhKg=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb h1:TLPQVbx1GJ8VKZxz52VAxl1EBgKXXbTiU9Fc5fZeLn4=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I=
google.golang.org/grpc v1.72.1 h1:HR03wO6eyZ7lknl75XlxABNVLLFc2PAb6mHlYh756mA=
google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d h1:VBu5YqKPv6XiJ199exd8Br+Aetz+o08F+PLMnwJQHAY=
google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4=
google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 h1:7whR9kGa5LUwFtpLm2ArCEejtnxlGeLbAyjFY8sGNFw=
google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157/go.mod h1:99sLkeliLXfdj2J75X3Ho+rrVCaJze0uwN7zDDkjPVU=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
@@ -287,42 +281,39 @@ gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
k8s.io/api v0.34.1 h1:jC+153630BMdlFukegoEL8E/yT7aLyQkIVuwhmwDgJM=
k8s.io/api v0.34.1/go.mod h1:SB80FxFtXn5/gwzCoN6QCtPD7Vbu5w2n1S0J5gFfTYk=
k8s.io/apiextensions-apiserver v0.34.1 h1:NNPBva8FNAPt1iSVwIE0FsdrVriRXMsaWFMqJbII2CI=
k8s.io/apiextensions-apiserver v0.34.1/go.mod h1:hP9Rld3zF5Ay2Of3BeEpLAToP+l4s5UlxiHfqRaRcMc=
k8s.io/apiserver v0.34.1 h1:U3JBGdgANK3dfFcyknWde1G6X1F4bg7PXuvlqt8lITA=
k8s.io/apiserver v0.34.1/go.mod h1:eOOc9nrVqlBI1AFCvVzsob0OxtPZUCPiUJL45JOTBG0=
k8s.io/client-go v0.34.1 h1:ZUPJKgXsnKwVwmKKdPfw4tB58+7/Ik3CrjOEhsiZ7mY=
k8s.io/client-go v0.34.1/go.mod h1:kA8v0FP+tk6sZA0yKLRG67LWjqufAoSHA2xVGKw9Of8=
k8s.io/component-base v0.34.1 h1:v7xFgG+ONhytZNFpIz5/kecwD+sUhVE6HU7qQUiRM4A=
k8s.io/component-base v0.34.1/go.mod h1:mknCpLlTSKHzAQJJnnHVKqjxR7gBeHRv0rPXA7gdtQ0=
k8s.io/api v0.31.2 h1:3wLBbL5Uom/8Zy98GRPXpJ254nEFpl+hwndmk9RwmL0=
k8s.io/api v0.31.2/go.mod h1:bWmGvrGPssSK1ljmLzd3pwCQ9MgoTsRCuK35u6SygUk=
k8s.io/apiextensions-apiserver v0.31.2 h1:W8EwUb8+WXBLu56ser5IudT2cOho0gAKeTOnywBLxd0=
k8s.io/apiextensions-apiserver v0.31.2/go.mod h1:i+Geh+nGCJEGiCGR3MlBDkS7koHIIKWVfWeRFiOsUcM=
k8s.io/apimachinery v0.31.2 h1:i4vUt2hPK56W6mlT7Ry+AO8eEsyxMD1U44NR22CLTYw=
k8s.io/apimachinery v0.31.2/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo=
k8s.io/apiserver v0.31.2 h1:VUzOEUGRCDi6kX1OyQ801m4A7AUPglpsmGvdsekmcI4=
k8s.io/apiserver v0.31.2/go.mod h1:o3nKZR7lPlJqkU5I3Ove+Zx3JuoFjQobGX1Gctw6XuE=
k8s.io/client-go v0.31.2 h1:Y2F4dxU5d3AQj+ybwSMqQnpZH9F30//1ObxOKlTI9yc=
k8s.io/client-go v0.31.2/go.mod h1:NPa74jSVR/+eez2dFsEIHNa+3o09vtNaWwWwb1qSxSs=
k8s.io/component-base v0.31.2 h1:Z1J1LIaC0AV+nzcPRFqfK09af6bZ4D1nAOpWsy9owlA=
k8s.io/component-base v0.31.2/go.mod h1:9PeyyFN/drHjtJZMCTkSpQJS3U9OXORnHQqMLDz0sUQ=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kms v0.34.1 h1:iCFOvewDPzWM9fMTfyIPO+4MeuZ0tcZbugxLNSHFG4w=
k8s.io/kms v0.34.1/go.mod h1:s1CFkLG7w9eaTYvctOxosx88fl4spqmixnNpys0JAtM=
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b h1:MloQ9/bdJyIu9lb1PzujOPolHyvO06MXG5TUIj2mNAA=
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b/go.mod h1:UZ2yyWbFTpuhSbFhv24aGNOdoRdJZgsIObGBUaYVsts=
k8s.io/utils v0.0.0-20250820121507-0af2bda4dd1d h1:wAhiDyZ4Tdtt7e46e9M5ZSAJ/MnPGPs+Ki1gHw4w1R0=
k8s.io/utils v0.0.0-20250820121507-0af2bda4dd1d/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 h1:jpcvIRr3GLoUoEKRkHKSmGjxb6lWwrBlJsXc+eUYQHM=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw=
sigs.k8s.io/controller-runtime v0.22.2 h1:cK2l8BGWsSWkXz09tcS4rJh95iOLney5eawcK5A33r4=
sigs.k8s.io/controller-runtime v0.22.2/go.mod h1:+QX1XUpTXN4mLoblf4tqr5CQcyHPAki2HLXqQMY6vh8=
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg=
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
sigs.k8s.io/structured-merge-diff/v4 v4.7.0 h1:qPeWmscJcXP0snki5IYF79Z8xrl8ETFxgMd7wez1XkI=
sigs.k8s.io/structured-merge-diff/v4 v4.7.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps=
sigs.k8s.io/structured-merge-diff/v6 v6.3.0 h1:jTijUJbW353oVOd9oTlifJqOGEkUw2jB/fXCbTiQEco=
sigs.k8s.io/structured-merge-diff/v6 v6.3.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE=
k8s.io/kms v0.31.2 h1:pyx7l2qVOkClzFMIWMVF/FxsSkgd+OIGH7DecpbscJI=
k8s.io/kms v0.31.2/go.mod h1:OZKwl1fan3n3N5FFxnW5C4V3ygrah/3YXeJWS3O6+94=
k8s.io/kube-openapi v0.0.0-20240827152857-f7e401e7b4c2 h1:GKE9U8BH16uynoxQii0auTjmmmuZ3O0LFMN6S0lPPhI=
k8s.io/kube-openapi v0.0.0-20240827152857-f7e401e7b4c2/go.mod h1:coRQXBK9NxO98XUv3ZD6AK3xzHCxV6+b7lrquKwaKzA=
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A=
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.0 h1:CPT0ExVicCzcpeN4baWEV2ko2Z/AsiZgEdwgcfwLgMo=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.0/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw=
sigs.k8s.io/controller-runtime v0.19.0 h1:nWVM7aq+Il2ABxwiCizrVDSlmDcshi9llbaFbC0ji/Q=
sigs.k8s.io/controller-runtime v0.19.0/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4=
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8=
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo=
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4=
sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08=
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs=
sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4=

View File

@@ -1,145 +0,0 @@
#!/bin/bash
###############################################################################
# check-optional-repos.sh - Check optional repositories for tags and commits #
# during a release period #
###############################################################################
set -eu
# Function to ensure repository is cloned and up-to-date
update_repo() {
local repo_name=$1
local repo_url="https://github.com/cozystack/${repo_name}.git"
mkdir -p _repos
cd _repos
if [ -d "$repo_name" ]; then
cd "$repo_name"
git fetch --all --tags --force
git checkout main 2>/dev/null || git checkout master
git pull
else
git clone "$repo_url"
cd "$repo_name"
fi
cd ../..
}
# Check if required parameters are provided
if [ $# -lt 2 ]; then
echo "Usage: $0 <RELEASE_START> <RELEASE_END>"
echo "Example: $0 '2025-10-10 12:27:31 +0400' '2025-10-13 16:04:33 +0200'"
exit 1
fi
RELEASE_START="$1"
RELEASE_END="$2"
# Get the script directory to return to it later
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
COZYSTACK_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$COZYSTACK_ROOT"
echo "Checking optional repositories for tags and commits between:"
echo " Start: $RELEASE_START"
echo " End: $RELEASE_END"
echo ""
# Loop through ALL optional repositories
for repo_name in talm boot-to-talos cozyhr cozy-proxy; do
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "Checking repository: $repo_name"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
# Update/clone repository
update_repo "$repo_name"
cd "_repos/$repo_name"
REPO_NAME=$(basename "$(pwd)")
git fetch --all --tags --force
# Check for tags matching release version pattern or created during release period
TAGS=$(git for-each-ref --format='%(refname:short) %(creatordate)' refs/tags 2>/dev/null | \
awk -v start="$RELEASE_START" -v end="$RELEASE_END" '$2 >= start && $2 <= end {print $1}' || true)
if [ -n "$TAGS" ]; then
echo "Found tags in $repo_name: $TAGS"
PREV_TAG=$(echo "$TAGS" | head -1)
NEW_TAG=$(echo "$TAGS" | tail -1)
echo ""
echo "Commits between $PREV_TAG and $NEW_TAG:"
# Include merge commits to capture backports
git log "$PREV_TAG..$NEW_TAG" --format="%H|%s|%an" 2>/dev/null | while IFS='|' read -r commit_hash subject author_name; do
if [ -z "$commit_hash" ]; then
continue
fi
# Get PR number from commit message
COMMIT_MSG=$(git log -1 --format=%B "$commit_hash" 2>/dev/null || echo "")
PR_NUMBER=$(echo "$COMMIT_MSG" | grep -oE '#[0-9]+' | head -1 | tr -d '#' || echo "")
# Get author: prioritize PR author, fallback to commit author
GITHUB_USERNAME=""
if [ -n "$PR_NUMBER" ]; then
GITHUB_USERNAME=$(gh pr view "$PR_NUMBER" --repo "cozystack/$REPO_NAME" --json author --jq '.author.login // empty' 2>/dev/null || echo "")
fi
if [ -z "$GITHUB_USERNAME" ]; then
GITHUB_USERNAME=$(gh api "repos/cozystack/$REPO_NAME/commits/$commit_hash" --jq '.author.login // empty' 2>/dev/null || echo "")
fi
if [ -n "$PR_NUMBER" ]; then
echo " $commit_hash|$subject|$author_name|$GITHUB_USERNAME|cozystack/$REPO_NAME#$PR_NUMBER"
else
echo " $commit_hash|$subject|$author_name|$GITHUB_USERNAME|cozystack/$REPO_NAME@${commit_hash:0:7}"
fi
done
else
echo "No tags found in $repo_name during release period"
# Check for commits by dates if no exact version tags
# Include merge commits to capture backports
COMMITS=$(git log --since="$RELEASE_START" --until="$RELEASE_END" --format="%H|%s|%an" 2>/dev/null || true)
if [ -n "$COMMITS" ]; then
echo ""
echo "Commits found by date range:"
echo "$COMMITS" | while IFS='|' read -r commit_hash subject author_name; do
if [ -z "$commit_hash" ]; then
continue
fi
# Get PR number from commit message
COMMIT_MSG=$(git log -1 --format=%B "$commit_hash" 2>/dev/null || echo "")
PR_NUMBER=$(echo "$COMMIT_MSG" | grep -oE '#[0-9]+' | head -1 | tr -d '#' || echo "")
# Get author: prioritize PR author, fallback to commit author
GITHUB_USERNAME=""
if [ -n "$PR_NUMBER" ]; then
GITHUB_USERNAME=$(gh pr view "$PR_NUMBER" --repo "cozystack/$REPO_NAME" --json author --jq '.author.login // empty' 2>/dev/null || echo "")
fi
if [ -z "$GITHUB_USERNAME" ]; then
GITHUB_USERNAME=$(gh api "repos/cozystack/$REPO_NAME/commits/$commit_hash" --jq '.author.login // empty' 2>/dev/null || echo "")
fi
if [ -n "$PR_NUMBER" ]; then
echo " $commit_hash|$subject|$author_name|$GITHUB_USERNAME|cozystack/$REPO_NAME#$PR_NUMBER"
else
echo " $commit_hash|$subject|$author_name|$GITHUB_USERNAME|cozystack/$REPO_NAME@${commit_hash:0:7}"
fi
done
else
echo "No commits found in $repo_name during release period"
fi
fi
echo ""
cd "$COZYSTACK_ROOT"
done
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "Finished checking all optional repositories"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"

View File

@@ -1,44 +0,0 @@
#!/usr/bin/env bats
@test "Create DB FerretDB" {
name='test'
kubectl apply -f - <<EOF
apiVersion: apps.cozystack.io/v1alpha1
kind: FerretDB
metadata:
name: $name
namespace: tenant-test
spec:
backup:
destinationPath: "s3://bucket/path/to/folder/"
enabled: false
endpointURL: "http://minio-gateway-service:9000"
retentionPolicy: "30d"
s3AccessKey: "<your-access-key>"
s3SecretKey: "<your-secret-key>"
schedule: "0 2 * * * *"
bootstrap:
enabled: false
external: false
quorum:
maxSyncReplicas: 0
minSyncReplicas: 0
replicas: 2
resources: {}
resourcesPreset: "micro"
size: "10Gi"
users:
testuser:
password: xai7Wepo
EOF
sleep 5
kubectl -n tenant-test wait hr ferretdb-$name --timeout=100s --for=condition=ready
timeout 40 sh -ec "until kubectl -n tenant-test get svc ferretdb-$name-postgres-r -o jsonpath='{.spec.ports[0].port}' | grep -q '5432'; do sleep 10; done"
timeout 40 sh -ec "until kubectl -n tenant-test get svc ferretdb-$name-postgres-ro -o jsonpath='{.spec.ports[0].port}' | grep -q '5432'; do sleep 10; done"
timeout 40 sh -ec "until kubectl -n tenant-test get svc ferretdb-$name-postgres-rw -o jsonpath='{.spec.ports[0].port}' | grep -q '5432'; do sleep 10; done"
timeout 120 sh -ec "until kubectl -n tenant-test get endpoints ferretdb-$name-postgres-r -o jsonpath='{.subsets[*].addresses[*].ip}' | grep -q '[0-9]'; do sleep 10; done"
# for some reason it takes longer for the read-only endpoint to be ready
#timeout 120 sh -ec "until kubectl -n tenant-test get endpoints ferretdb-$name-postgres-ro -o jsonpath='{.subsets[*].addresses[*].ip}' | grep -q '[0-9]'; do sleep 10; done"
timeout 120 sh -ec "until kubectl -n tenant-test get endpoints ferretdb-$name-postgres-rw -o jsonpath='{.subsets[*].addresses[*].ip}' | grep -q '[0-9]'; do sleep 10; done"
kubectl -n tenant-test delete ferretdb.apps.cozystack.io $name
}

View File

@@ -1,121 +0,0 @@
#!/usr/bin/env bats
@test "Create DB FoundationDB" {
name='test'
kubectl apply -f - <<EOF
apiVersion: apps.cozystack.io/v1alpha1
kind: FoundationDB
metadata:
name: $name
namespace: tenant-test
spec:
cluster:
version: "7.3.63"
processCounts:
storage: 3
stateless: -1
cluster_controller: 1
redundancyMode: "double"
storageEngine: "ssd-2"
faultDomain:
key: "foundationdb.org/none"
valueFrom: "\$FDB_ZONE_ID"
storage:
size: "1Gi"
storageClass: ""
resourcesPreset: "small"
backup:
enabled: false
s3:
bucket: ""
endpoint: ""
region: ""
credentials:
accessKeyId: ""
secretAccessKey: ""
retentionPolicy: "7d"
monitoring:
enabled: true
customParameters:
- "knob_disable_posix_kernel_aio=1"
imageType: "unified"
automaticReplacements: true
EOF
sleep 15
# Wait for HelmRelease to be ready
kubectl -n tenant-test wait hr foundationdb-$name --timeout=300s --for=condition=ready
# Wait for FoundationDBCluster to be created (name has foundationdb- prefix)
timeout 300 sh -ec "until kubectl -n tenant-test get foundationdbclusters.apps.foundationdb.org foundationdb-$name; do sleep 15; done"
# Wait for cluster to become available (initial reconciliation takes time - allow 5 minutes)
timeout 300 sh -ec "until kubectl -n tenant-test get foundationdbclusters.apps.foundationdb.org foundationdb-$name -o jsonpath='{.status.databaseConfiguration.usable_regions}' | grep -q '1'; do sleep 30; done"
# Check that storage processes are running
timeout 300 sh -ec "until [ \$(kubectl -n tenant-test get pods -l foundationdb.org/fdb-cluster-name=foundationdb-$name,foundationdb.org/fdb-process-class=storage --field-selector=status.phase=Running --no-headers | wc -l) -eq 3 ]; do sleep 15; done"
# Check that log processes are running (these are the stateless processes)
timeout 300 sh -ec "until [ \$(kubectl -n tenant-test get pods -l foundationdb.org/fdb-cluster-name=foundationdb-$name,foundationdb.org/fdb-process-class=log --field-selector=status.phase=Running --no-headers | wc -l) -ge 1 ]; do sleep 15; done"
# Check that cluster controller is running
timeout 300 sh -ec "until [ \$(kubectl -n tenant-test get pods -l foundationdb.org/fdb-cluster-name=foundationdb-$name,foundationdb.org/fdb-process-class=cluster_controller --field-selector=status.phase=Running --no-headers | wc -l) -eq 1 ]; do sleep 15; done"
# Check WorkloadMonitor is created and configured
timeout 120 sh -ec "until kubectl -n tenant-test get workloadmonitor foundationdb-$name; do sleep 10; done"
timeout 60 sh -ec "until kubectl -n tenant-test get workloadmonitor foundationdb-$name -o jsonpath='{.spec.replicas}' | grep -q '3'; do sleep 5; done"
# Check dashboard resource map is created
kubectl -n tenant-test get configmap foundationdb-$name-resourcemap
# Verify cluster is healthy (check cluster status) - allow extra time for initial setup
timeout 300 sh -ec "until kubectl -n tenant-test get foundationdbclusters.apps.foundationdb.org foundationdb-$name -o jsonpath='{.status.health.available}' | grep -q 'true'; do sleep 20; done"
# Validate status.configured field
timeout 60 sh -ec "until kubectl -n tenant-test get foundationdbclusters.apps.foundationdb.org foundationdb-$name -o jsonpath='{.status.configured}' | grep -q 'true'; do sleep 10; done"
# Validate status.connectionString field exists and contains expected format
timeout 60 sh -ec "until kubectl -n tenant-test get foundationdbclusters.apps.foundationdb.org foundationdb-$name -o jsonpath='{.status.connectionString}' | grep -q '@.*\.svc\.cozy\.local'; do sleep 10; done"
# Validate comprehensive status.databaseConfiguration fields
timeout 60 sh -ec "until kubectl -n tenant-test get foundationdbclusters.apps.foundationdb.org foundationdb-$name -o jsonpath='{.status.databaseConfiguration.logs}' | grep -q '3'; do sleep 10; done"
timeout 60 sh -ec "until kubectl -n tenant-test get foundationdbclusters.apps.foundationdb.org foundationdb-$name -o jsonpath='{.status.databaseConfiguration.proxies}' | grep -q '3'; do sleep 10; done"
timeout 60 sh -ec "until kubectl -n tenant-test get foundationdbclusters.apps.foundationdb.org foundationdb-$name -o jsonpath='{.status.databaseConfiguration.redundancy_mode}' | grep -q 'double'; do sleep 10; done"
timeout 60 sh -ec "until kubectl -n tenant-test get foundationdbclusters.apps.foundationdb.org foundationdb-$name -o jsonpath='{.status.databaseConfiguration.resolvers}' | grep -q '1'; do sleep 10; done"
timeout 60 sh -ec "until kubectl -n tenant-test get foundationdbclusters.apps.foundationdb.org foundationdb-$name -o jsonpath='{.status.databaseConfiguration.storage_engine}' | grep -q 'ssd-2'; do sleep 10; done"
timeout 60 sh -ec "until kubectl -n tenant-test get foundationdbclusters.apps.foundationdb.org foundationdb-$name -o jsonpath='{.status.databaseConfiguration.usable_regions}' | grep -q '1'; do sleep 10; done"
# Validate status.desiredProcessGroups field
timeout 60 sh -ec "until kubectl -n tenant-test get foundationdbclusters.apps.foundationdb.org foundationdb-$name -o jsonpath='{.status.desiredProcessGroups}' | grep -q '^[0-9][0-9]*$'; do sleep 10; done"
# Validate status.generations.reconciled field
timeout 60 sh -ec "until kubectl -n tenant-test get foundationdbclusters.apps.foundationdb.org foundationdb-$name -o jsonpath='{.status.generations.reconciled}' | grep -q '^[0-9][0-9]*$'; do sleep 10; done"
# Validate status.hasListenIPsForAllPods field
timeout 60 sh -ec "until kubectl -n tenant-test get foundationdbclusters.apps.foundationdb.org foundationdb-$name -o jsonpath='{.status.hasListenIPsForAllPods}' | grep -q 'true'; do sleep 10; done"
# Validate comprehensive status.health fields
timeout 60 sh -ec "until kubectl -n tenant-test get foundationdbclusters.apps.foundationdb.org foundationdb-$name -o jsonpath='{.status.health.fullReplication}' | grep -q 'true'; do sleep 10; done"
timeout 60 sh -ec "until kubectl -n tenant-test get foundationdbclusters.apps.foundationdb.org foundationdb-$name -o jsonpath='{.status.health.healthy}' | grep -q 'true'; do sleep 10; done"
# Verify security context is applied correctly (non-root user)
storage_pod=$(kubectl -n tenant-test get pods -l foundationdb.org/fdb-cluster-name=foundationdb-$name,foundationdb.org/fdb-process-class=storage --no-headers | head -n1 | awk '{print $1}')
kubectl -n tenant-test get pod "$storage_pod" -o jsonpath='{.spec.containers[0].securityContext.runAsUser}' | grep -q '4059'
kubectl -n tenant-test get pod "$storage_pod" -o jsonpath='{.spec.containers[0].securityContext.runAsGroup}' | grep -q '4059'
# Verify volumeClaimTemplate is properly configured in FoundationDBCluster CRD
timeout 60 sh -ec "until kubectl -n tenant-test get foundationdbclusters.apps.foundationdb.org foundationdb-$name -o jsonpath='{.spec.processes.general.volumeClaimTemplate.spec.resources.requests.storage}' | grep -q '1Gi'; do sleep 10; done"
# Verify PVCs are created with correct storage size (1Gi as specified in test)
timeout 120 sh -ec "until [ \$(kubectl -n tenant-test get pvc -l foundationdb.org/fdb-cluster-name=foundationdb-$name --no-headers | wc -l) -ge 3 ]; do sleep 10; done"
kubectl -n tenant-test get pvc -l foundationdb.org/fdb-cluster-name=foundationdb-$name -o jsonpath='{.items[*].spec.resources.requests.storage}' | grep -q '1Gi'
# Verify actual PVC storage capacity matches requested size
kubectl -n tenant-test get pvc -l foundationdb.org/fdb-cluster-name=foundationdb-$name -o jsonpath='{.items[*].status.capacity.storage}' | grep -q '1Gi'
# Clean up
kubectl -n tenant-test delete foundationdb $name
# Wait for cleanup to complete
timeout 120 sh -ec "while kubectl -n tenant-test get foundationdbclusters.apps.foundationdb.org foundationdb-$name 2>/dev/null; do sleep 10; done"
}

View File

@@ -1,31 +0,0 @@
#!/usr/bin/env bats
@test "Create DB MongoDB" {
name='test'
kubectl apply -f - <<EOF
apiVersion: apps.cozystack.io/v1alpha1
kind: MongoDB
metadata:
name: $name
namespace: tenant-test
spec:
external: false
size: 10Gi
replicas: 1
storageClass: ""
resourcesPreset: "nano"
backup:
enabled: false
EOF
sleep 5
# Wait for HelmRelease
kubectl -n tenant-test wait hr mongodb-$name --timeout=60s --for=condition=ready
# Wait for MongoDB service (port 27017)
timeout 120 sh -ec "until kubectl -n tenant-test get svc mongodb-$name-rs0 -o jsonpath='{.spec.ports[0].port}' | grep -q '27017'; do sleep 10; done"
# Wait for endpoints
timeout 180 sh -ec "until kubectl -n tenant-test get endpoints mongodb-$name-rs0 -o jsonpath='{.subsets[*].addresses[*].ip}' | grep -q '[0-9]'; do sleep 10; done"
# Wait for StatefulSet replicas
kubectl -n tenant-test wait statefulset.apps/mongodb-$name-rs0 --timeout=300s --for=jsonpath='{.status.replicas}'=1
# Cleanup
kubectl -n tenant-test delete mongodbs.apps.cozystack.io $name
}

View File

@@ -72,7 +72,7 @@ EOF
kubectl wait --for=condition=TenantControlPlaneCreated kamajicontrolplane -n tenant-test kubernetes-${test_name} --timeout=4m
# Wait for Kubernetes resources to be ready (timeout after 2 minutes)
kubectl wait tcp -n tenant-test kubernetes-${test_name} --timeout=5m --for=jsonpath='{.status.kubernetesResources.version.status}'=Ready
kubectl wait tcp -n tenant-test kubernetes-${test_name} --timeout=2m --for=jsonpath='{.status.kubernetesResources.version.status}'=Ready
# Wait for all required deployments to be available (timeout after 4 minutes)
kubectl wait deploy --timeout=4m --for=condition=available -n tenant-test kubernetes-${test_name} kubernetes-${test_name}-cluster-autoscaler kubernetes-${test_name}-kccm kubernetes-${test_name}-kcsi-controller
@@ -80,41 +80,58 @@ EOF
# Wait for the machine deployment to scale to 2 replicas (timeout after 1 minute)
kubectl wait machinedeployment kubernetes-${test_name}-md0 -n tenant-test --timeout=1m --for=jsonpath='{.status.replicas}'=2
# Get the admin kubeconfig and save it to a file
kubectl get secret kubernetes-${test_name}-admin-kubeconfig -ojsonpath='{.data.super-admin\.conf}' -n tenant-test | base64 -d > tenantkubeconfig-${test_name}
kubectl get secret kubernetes-${test_name}-admin-kubeconfig -ojsonpath='{.data.super-admin\.conf}' -n tenant-test | base64 -d > tenantkubeconfig
# Update the kubeconfig to use localhost for the API server
yq -i ".clusters[0].cluster.server = \"https://localhost:${port}\"" tenantkubeconfig-${test_name}
yq -i ".clusters[0].cluster.server = \"https://localhost:${port}\"" tenantkubeconfig
# Set up port forwarding to the Kubernetes API server for a 200 second timeout
bash -c 'timeout 500s kubectl port-forward service/kubernetes-'"${test_name}"' -n tenant-test '"${port}"':6443 > /dev/null 2>&1 &'
bash -c 'timeout 300s kubectl port-forward service/kubernetes-'"${test_name}"' -n tenant-test '"${port}"':6443 > /dev/null 2>&1 &'
# Verify the Kubernetes version matches what we expect (retry for up to 20 seconds)
timeout 20 sh -ec 'until kubectl --kubeconfig tenantkubeconfig-'"${test_name}"' version 2>/dev/null | grep -Fq "Server Version: ${k8s_version}"; do sleep 5; done'
timeout 20 sh -ec 'until kubectl --kubeconfig tenantkubeconfig version 2>/dev/null | grep -Fq "Server Version: ${k8s_version}"; do sleep 5; done'
# Wait for the nodes to be ready (timeout after 2 minutes)
timeout 3m bash -c '
until [ "$(kubectl --kubeconfig tenantkubeconfig-'"${test_name}"' get nodes -o jsonpath="{.items[*].metadata.name}" | wc -w)" -eq 2 ]; do
until [ "$(kubectl --kubeconfig tenantkubeconfig get nodes -o jsonpath="{.items[*].metadata.name}" | wc -w)" -eq 2 ]; do
sleep 2
done
'
# Verify the nodes are ready
kubectl --kubeconfig tenantkubeconfig-${test_name} wait node --all --timeout=2m --for=condition=Ready
kubectl --kubeconfig tenantkubeconfig-${test_name} get nodes -o wide
kubectl --kubeconfig tenantkubeconfig wait node --all --timeout=2m --for=condition=Ready
kubectl --kubeconfig tenantkubeconfig get nodes -o wide
# Verify the kubelet version matches what we expect
versions=$(kubectl --kubeconfig "tenantkubeconfig-${test_name}" \
get nodes -o jsonpath='{.items[*].status.nodeInfo.kubeletVersion}')
versions=$(kubectl --kubeconfig tenantkubeconfig get nodes -o jsonpath='{.items[*].status.nodeInfo.kubeletVersion}')
node_ok=true
case "$k8s_version" in
v1.32*)
echo "⚠️ TODO: Temporary stub — allowing nodes with v1.33 while k8s_version is v1.32"
;;
esac
for v in $versions; do
case "$v" in
"${k8s_version}" | "${k8s_version}".* | "${k8s_version}"-*)
# acceptable
case "$k8s_version" in
v1.32|v1.32.*)
case "$v" in
v1.32 | v1.32.* | v1.32-* | v1.33 | v1.33.* | v1.33-*)
;;
*)
node_ok=false
break
;;
esac
;;
*)
node_ok=false
break
case "$v" in
"${k8s_version}" | "${k8s_version}".* | "${k8s_version}"-*)
;;
*)
node_ok=false
break
;;
esac
;;
esac
done
@@ -124,100 +141,6 @@ EOF
exit 1
fi
kubectl --kubeconfig tenantkubeconfig-${test_name} apply -f - <<EOF
apiVersion: v1
kind: Namespace
metadata:
name: tenant-test
EOF
# Backend 1
kubectl apply --kubeconfig tenantkubeconfig-${test_name} -f- <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: "${test_name}-backend"
namespace: tenant-test
spec:
replicas: 1
selector:
matchLabels:
app: backend
backend: "${test_name}-backend"
template:
metadata:
labels:
app: backend
backend: "${test_name}-backend"
spec:
containers:
- name: nginx
image: nginx:alpine
ports:
- containerPort: 80
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 2
periodSeconds: 2
EOF
# LoadBalancer Service
kubectl apply --kubeconfig tenantkubeconfig-${test_name} -f- <<EOF
apiVersion: v1
kind: Service
metadata:
name: "${test_name}-backend"
namespace: tenant-test
spec:
type: LoadBalancer
selector:
app: backend
backend: "${test_name}-backend"
ports:
- port: 80
targetPort: 80
EOF
# Wait for pods readiness
kubectl wait deployment --kubeconfig tenantkubeconfig-${test_name} ${test_name}-backend -n tenant-test --for=condition=Available --timeout=90s
# Wait for LoadBalancer to be provisioned (IP or hostname)
timeout 90 sh -ec "
until kubectl get svc ${test_name}-backend --kubeconfig tenantkubeconfig-${test_name} -n tenant-test \
-o jsonpath='{.status.loadBalancer.ingress[0]}' | grep -q .; do
sleep 5
done
"
LB_ADDR=$(
kubectl get svc --kubeconfig tenantkubeconfig-${test_name} "${test_name}-backend" \
-n tenant-test \
-o jsonpath='{.status.loadBalancer.ingress[0].ip}{.status.loadBalancer.ingress[0].hostname}'
)
if [ -z "$LB_ADDR" ]; then
echo "LoadBalancer address is empty" >&2
exit 1
fi
for i in $(seq 1 20); do
echo "Attempt $i"
curl --silent --fail "http://${LB_ADDR}" && break
sleep 3
done
if [ "$i" -eq 20 ]; then
echo "LoadBalancer not reachable" >&2
exit 1
fi
# Cleanup
kubectl delete deployment --kubeconfig tenantkubeconfig-${test_name} "${test_name}-backend" -n tenant-test
kubectl delete service --kubeconfig tenantkubeconfig-${test_name} "${test_name}-backend" -n tenant-test
# Wait for all machine deployment replicas to be ready (timeout after 10 minutes)
kubectl wait machinedeployment kubernetes-${test_name}-md0 -n tenant-test --timeout=10m --for=jsonpath='{.status.v1beta2.readyReplicas}'=2

View File

@@ -19,35 +19,3 @@
curl -sS --fail 'http://localhost:21234/openapi/v2?timeout=32s' -H 'Accept: application/com.github.proto-openapi.spec.v2@v1.0+protobuf' > /dev/null
)
}
@test "Test kinds" {
val=$(kubectl get --raw /apis/apps.cozystack.io/v1alpha1/tenants | jq -r '.kind')
if [ "$val" != "TenantList" ]; then
echo "Expected kind to be TenantList, got $val"
exit 1
fi
val=$(kubectl get --raw /apis/apps.cozystack.io/v1alpha1/tenants | jq -r '.items[0].kind')
if [ "$val" != "Tenant" ]; then
echo "Expected kind to be Tenant, got $val"
exit 1
fi
val=$(kubectl get --raw /apis/apps.cozystack.io/v1alpha1/ingresses | jq -r '.kind')
if [ "$val" != "IngressList" ]; then
echo "Expected kind to be IngressList, got $val"
exit 1
fi
val=$(kubectl get --raw /apis/apps.cozystack.io/v1alpha1/ingresses | jq -r '.items[0].kind')
if [ "$val" != "Ingress" ]; then
echo "Expected kind to be Ingress, got $val"
exit 1
fi
}
@test "Create and delete namespace" {
kubectl create ns cozy-test-create-and-delete-namespace --dry-run=client -o yaml | kubectl apply -f -
if ! kubectl delete ns cozy-test-create-and-delete-namespace; then
echo "Failed to delete namespace"
kubectl describe ns cozy-test-create-and-delete-namespace
exit 1
fi
}

View File

@@ -1,59 +0,0 @@
#!/bin/sh
set -eu
# Script to run unit tests for all Helm charts.
# It iterates through directories in packages/apps, packages/extra,
# packages/system, and packages/library and runs the 'test' Makefile
# target if it exists.
FAILED_DIRS_FILE="$(mktemp)"
trap 'rm -f "$FAILED_DIRS_FILE"' EXIT
tests_found=0
check_and_run_test() {
dir="$1"
makefile="$dir/Makefile"
if [ ! -f "$makefile" ]; then
return 0
fi
if make -C "$dir" -n test >/dev/null 2>&1; then
echo "Running tests in $dir"
tests_found=$((tests_found + 1))
if ! make -C "$dir" test; then
printf '%s\n' "$dir" >> "$FAILED_DIRS_FILE"
return 1
fi
fi
return 0
}
for package_dir in packages/apps packages/extra packages/system packages/library; do
if [ ! -d "$package_dir" ]; then
echo "Warning: Directory $package_dir does not exist, skipping..." >&2
continue
fi
for dir in "$package_dir"/*; do
[ -d "$dir" ] || continue
check_and_run_test "$dir" || true
done
done
if [ "$tests_found" -eq 0 ]; then
echo "No directories with 'test' Makefile targets found."
exit 0
fi
if [ -s "$FAILED_DIRS_FILE" ]; then
echo "ERROR: Tests failed in the following directories:" >&2
while IFS= read -r dir; do
echo " - $dir" >&2
done < "$FAILED_DIRS_FILE"
exit 1
fi
echo "All Helm unit tests passed."

View File

@@ -8,6 +8,7 @@ need yq; need jq; need base64
CHART_YAML="${CHART_YAML:-Chart.yaml}"
VALUES_YAML="${VALUES_YAML:-values.yaml}"
SCHEMA_JSON="${SCHEMA_JSON:-values.schema.json}"
CRD_DIR="../../system/cozystack-resource-definitions/cozyrds"
[[ -f "$CHART_YAML" ]] || { echo "No $CHART_YAML found"; exit 1; }
[[ -f "$SCHEMA_JSON" ]] || { echo "No $SCHEMA_JSON found"; exit 1; }
@@ -21,8 +22,6 @@ if [[ -z "$NAME" ]]; then
echo "Chart.yaml: .name is empty"; exit 1
fi
CRD_DIR="../../system/${NAME}-rd/cozyrds"
# Resolve icon path
# Accepts:
# /logos/foo.svg -> ./logos/foo.svg

View File

@@ -1,40 +0,0 @@
#!/bin/sh
if [ $# -ne 1 ]; then
echo "Usage: $0 <version>"
echo "Example: 0.37.*"
exit 1
fi
VERSION_PATTERN="$1"
# Collect matching files first
FILES=$(find docs/changelogs -name "v${VERSION_PATTERN}.md" 2>/dev/null || true)
if [ -z "$FILES" ]; then
echo "No changelog files found matching pattern: v${VERSION_PATTERN}.md"
exit 1
fi
# Process each file
echo "$FILES" | while IFS= read -r file; do
if [ -z "$file" ]; then
continue
fi
# Extract version from filename safely (basename without extension)
version=$(basename "$file" .md)
if [ -z "$version" ]; then
echo "Warning: Could not extract version from file: $file"
continue
fi
echo "Uploading release notes for version: $version"
# Check exit status of gh release edit
if ! gh release edit "$version" --notes-file "docs/changelogs/${version}.md"; then
echo "Error: Failed to upload release notes for version: $version"
exit 1
fi
done

View File

@@ -37,8 +37,6 @@ type CozystackResourceDefinitionReconciler struct {
}
func (r *CozystackResourceDefinitionReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
// Only handle debounced restart logic
// HelmRelease reconciliation is handled by CozystackResourceDefinitionHelmReconciler
return r.debouncedRestart(ctx)
}

View File

@@ -1,201 +0,0 @@
package controller
import (
"context"
"fmt"
cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1"
helmv2 "github.com/fluxcd/helm-controller/api/v2"
"k8s.io/apimachinery/pkg/runtime"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/log"
)
// +kubebuilder:rbac:groups=cozystack.io,resources=cozystackresourcedefinitions,verbs=get;list;watch
// +kubebuilder:rbac:groups=helm.toolkit.fluxcd.io,resources=helmreleases,verbs=get;list;watch;update;patch
// CozystackResourceDefinitionHelmReconciler reconciles CozystackResourceDefinitions
// and updates related HelmReleases when a CozyRD changes.
// This controller does NOT watch HelmReleases to avoid mutual reconciliation storms
// with Flux's helm-controller.
type CozystackResourceDefinitionHelmReconciler struct {
client.Client
Scheme *runtime.Scheme
}
func (r *CozystackResourceDefinitionHelmReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
logger := log.FromContext(ctx)
// Get the CozystackResourceDefinition that triggered this reconciliation
crd := &cozyv1alpha1.CozystackResourceDefinition{}
if err := r.Get(ctx, req.NamespacedName, crd); err != nil {
logger.Error(err, "failed to get CozystackResourceDefinition", "name", req.Name)
return ctrl.Result{}, client.IgnoreNotFound(err)
}
// Update HelmReleases related to this specific CozyRD
if err := r.updateHelmReleasesForCRD(ctx, crd); err != nil {
logger.Error(err, "failed to update HelmReleases for CRD", "crd", crd.Name)
return ctrl.Result{}, err
}
return ctrl.Result{}, nil
}
func (r *CozystackResourceDefinitionHelmReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
Named("cozystackresourcedefinition-helm-reconciler").
For(&cozyv1alpha1.CozystackResourceDefinition{}).
Complete(r)
}
// updateHelmReleasesForCRD updates all HelmReleases that match the application labels from CozystackResourceDefinition
func (r *CozystackResourceDefinitionHelmReconciler) updateHelmReleasesForCRD(ctx context.Context, crd *cozyv1alpha1.CozystackResourceDefinition) error {
logger := log.FromContext(ctx)
// Use application labels to find HelmReleases
// Labels: apps.cozystack.io/application.kind and apps.cozystack.io/application.group
applicationKind := crd.Spec.Application.Kind
// Validate that applicationKind is non-empty
if applicationKind == "" {
logger.V(4).Info("Skipping HelmRelease update: Application.Kind is empty", "crd", crd.Name)
return nil
}
applicationGroup := "apps.cozystack.io" // All applications use this group
// Build label selector for HelmReleases
// Only reconcile HelmReleases with cozystack.io/ui=true label
labelSelector := client.MatchingLabels{
"apps.cozystack.io/application.kind": applicationKind,
"apps.cozystack.io/application.group": applicationGroup,
"cozystack.io/ui": "true",
}
// List all HelmReleases with matching labels
hrList := &helmv2.HelmReleaseList{}
if err := r.List(ctx, hrList, labelSelector); err != nil {
logger.Error(err, "failed to list HelmReleases", "kind", applicationKind, "group", applicationGroup)
return err
}
logger.V(4).Info("Found HelmReleases to update", "crd", crd.Name, "kind", applicationKind, "count", len(hrList.Items))
// Update each HelmRelease
for i := range hrList.Items {
hr := &hrList.Items[i]
if err := r.updateHelmReleaseChart(ctx, hr, crd); err != nil {
logger.Error(err, "failed to update HelmRelease", "name", hr.Name, "namespace", hr.Namespace)
continue
}
}
return nil
}
// expectedValuesFrom returns the expected valuesFrom configuration for HelmReleases
func expectedValuesFrom() []helmv2.ValuesReference {
return []helmv2.ValuesReference{
{
Kind: "Secret",
Name: "cozystack-values",
},
}
}
// valuesFromEqual compares two ValuesReference slices
func valuesFromEqual(a, b []helmv2.ValuesReference) bool {
if len(a) != len(b) {
return false
}
for i := range a {
if a[i].Kind != b[i].Kind ||
a[i].Name != b[i].Name ||
a[i].ValuesKey != b[i].ValuesKey ||
a[i].TargetPath != b[i].TargetPath ||
a[i].Optional != b[i].Optional {
return false
}
}
return true
}
// updateHelmReleaseChart updates the chart and valuesFrom in HelmRelease based on CozystackResourceDefinition
func (r *CozystackResourceDefinitionHelmReconciler) updateHelmReleaseChart(ctx context.Context, hr *helmv2.HelmRelease, crd *cozyv1alpha1.CozystackResourceDefinition) error {
logger := log.FromContext(ctx)
hrCopy := hr.DeepCopy()
updated := false
// Validate Chart configuration exists
if crd.Spec.Release.Chart.Name == "" {
logger.V(4).Info("Skipping HelmRelease chart update: Chart.Name is empty", "crd", crd.Name)
return nil
}
// Validate SourceRef fields
if crd.Spec.Release.Chart.SourceRef.Kind == "" ||
crd.Spec.Release.Chart.SourceRef.Name == "" ||
crd.Spec.Release.Chart.SourceRef.Namespace == "" {
logger.Error(fmt.Errorf("invalid SourceRef in CRD"), "Skipping HelmRelease chart update: SourceRef fields are incomplete",
"crd", crd.Name,
"kind", crd.Spec.Release.Chart.SourceRef.Kind,
"name", crd.Spec.Release.Chart.SourceRef.Name,
"namespace", crd.Spec.Release.Chart.SourceRef.Namespace)
return nil
}
// Get version and reconcileStrategy from CRD or use defaults
version := ">= 0.0.0-0"
reconcileStrategy := "Revision"
// TODO: Add Version and ReconcileStrategy fields to CozystackResourceDefinitionChart if needed
// Build expected SourceRef
expectedSourceRef := helmv2.CrossNamespaceObjectReference{
Kind: crd.Spec.Release.Chart.SourceRef.Kind,
Name: crd.Spec.Release.Chart.SourceRef.Name,
Namespace: crd.Spec.Release.Chart.SourceRef.Namespace,
}
if hrCopy.Spec.Chart == nil {
// Need to create Chart spec
hrCopy.Spec.Chart = &helmv2.HelmChartTemplate{
Spec: helmv2.HelmChartTemplateSpec{
Chart: crd.Spec.Release.Chart.Name,
Version: version,
ReconcileStrategy: reconcileStrategy,
SourceRef: expectedSourceRef,
},
}
updated = true
} else {
// Update existing Chart spec
if hrCopy.Spec.Chart.Spec.Chart != crd.Spec.Release.Chart.Name ||
hrCopy.Spec.Chart.Spec.SourceRef != expectedSourceRef {
hrCopy.Spec.Chart.Spec.Chart = crd.Spec.Release.Chart.Name
hrCopy.Spec.Chart.Spec.SourceRef = expectedSourceRef
updated = true
}
}
// Check and update valuesFrom configuration
expected := expectedValuesFrom()
if !valuesFromEqual(hrCopy.Spec.ValuesFrom, expected) {
logger.V(4).Info("Updating HelmRelease valuesFrom", "name", hr.Name, "namespace", hr.Namespace)
hrCopy.Spec.ValuesFrom = expected
updated = true
}
if updated {
logger.V(4).Info("Updating HelmRelease chart", "name", hr.Name, "namespace", hr.Namespace)
if err := r.Update(ctx, hrCopy); err != nil {
return fmt.Errorf("failed to update HelmRelease: %w", err)
}
}
return nil
}

View File

@@ -34,6 +34,9 @@ func (m *Manager) ensureCustomColumnsOverride(ctx context.Context, crd *cozyv1al
obj.SetName(name)
href := fmt.Sprintf("/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/%s/{reqsJsonPath[0]['.metadata.name']['-']}", detailsSegment)
if g == "apps.cozystack.io" && kind == "Tenant" && plural == "tenants" {
href = "/openapi-ui/{2}/{reqsJsonPath[0]['.status.namespace']['-']}/api-table/core.cozystack.io/v1alpha1/tenantmodules"
}
desired := map[string]any{
"spec": map[string]any{

View File

@@ -105,26 +105,8 @@ func buildMultilineStringSchema(openAPISchema string) (map[string]any, error) {
"properties": map[string]any{},
}
// Check if there's a spec property
specProp, ok := props["spec"].(map[string]any)
if !ok {
return map[string]any{}, nil
}
specProps, ok := specProp["properties"].(map[string]any)
if !ok {
return map[string]any{}, nil
}
// Create spec.properties structure in schema
schemaProps := schema["properties"].(map[string]any)
specSchema := map[string]any{
"properties": map[string]any{},
}
schemaProps["spec"] = specSchema
// Process spec properties recursively
processSpecProperties(specProps, specSchema["properties"].(map[string]any))
processSpecProperties(props, schema["properties"].(map[string]any))
return schema, nil
}

View File

@@ -9,46 +9,41 @@ func TestBuildMultilineStringSchema(t *testing.T) {
// Test OpenAPI schema with various field types
openAPISchema := `{
"properties": {
"spec": {
"simpleString": {
"type": "string",
"description": "A simple string field"
},
"stringWithEnum": {
"type": "string",
"enum": ["option1", "option2"],
"description": "String with enum should be skipped"
},
"numberField": {
"type": "number",
"description": "Number field should be skipped"
},
"nestedObject": {
"type": "object",
"properties": {
"simpleString": {
"nestedString": {
"type": "string",
"description": "A simple string field"
"description": "Nested string should get multilineString"
},
"stringWithEnum": {
"nestedStringWithEnum": {
"type": "string",
"enum": ["option1", "option2"],
"description": "String with enum should be skipped"
},
"numberField": {
"type": "number",
"description": "Number field should be skipped"
},
"nestedObject": {
"type": "object",
"properties": {
"nestedString": {
"type": "string",
"description": "Nested string should get multilineString"
},
"nestedStringWithEnum": {
"type": "string",
"enum": ["a", "b"],
"description": "Nested string with enum should be skipped"
}
}
},
"arrayOfObjects": {
"type": "array",
"items": {
"type": "object",
"properties": {
"itemString": {
"type": "string",
"description": "String in array item"
}
}
"enum": ["a", "b"],
"description": "Nested string with enum should be skipped"
}
}
},
"arrayOfObjects": {
"type": "array",
"items": {
"type": "object",
"properties": {
"itemString": {
"type": "string",
"description": "String in array item"
}
}
}
@@ -75,44 +70,33 @@ func TestBuildMultilineStringSchema(t *testing.T) {
t.Fatal("schema.properties is not a map")
}
// Check spec property exists
spec, ok := props["spec"].(map[string]any)
if !ok {
t.Fatal("spec not found in properties")
}
specProps, ok := spec["properties"].(map[string]any)
if !ok {
t.Fatal("spec.properties is not a map")
}
// Check simpleString
simpleString, ok := specProps["simpleString"].(map[string]any)
simpleString, ok := props["simpleString"].(map[string]any)
if !ok {
t.Fatal("simpleString not found in spec.properties")
t.Fatal("simpleString not found in properties")
}
if simpleString["type"] != "multilineString" {
t.Errorf("simpleString should have type multilineString, got %v", simpleString["type"])
}
// Check stringWithEnum should not be present (or should not have multilineString)
if stringWithEnum, ok := specProps["stringWithEnum"].(map[string]any); ok {
if stringWithEnum, ok := props["stringWithEnum"].(map[string]any); ok {
if stringWithEnum["type"] == "multilineString" {
t.Error("stringWithEnum should not have multilineString type")
}
}
// Check numberField should not be present
if numberField, ok := specProps["numberField"].(map[string]any); ok {
if numberField, ok := props["numberField"].(map[string]any); ok {
if numberField["type"] != nil {
t.Error("numberField should not have any type override")
}
}
// Check nested object
nestedObject, ok := specProps["nestedObject"].(map[string]any)
nestedObject, ok := props["nestedObject"].(map[string]any)
if !ok {
t.Fatal("nestedObject not found in spec.properties")
t.Fatal("nestedObject not found in properties")
}
nestedProps, ok := nestedObject["properties"].(map[string]any)
if !ok {
@@ -129,9 +113,9 @@ func TestBuildMultilineStringSchema(t *testing.T) {
}
// Check array of objects
arrayOfObjects, ok := specProps["arrayOfObjects"].(map[string]any)
arrayOfObjects, ok := props["arrayOfObjects"].(map[string]any)
if !ok {
t.Fatal("arrayOfObjects not found in spec.properties")
t.Fatal("arrayOfObjects not found in properties")
}
items, ok := arrayOfObjects["items"].(map[string]any)
if !ok {

View File

@@ -44,9 +44,6 @@ func (m *Manager) ensureFactory(ctx context.Context, crd *cozyv1alpha1.Cozystack
if flags.Secrets {
tabs = append(tabs, secretsTab(kind))
}
if prefix, ok := vncTabPrefix(kind); ok {
tabs = append(tabs, vncTab(prefix))
}
tabs = append(tabs, yamlTab(plural))
// Use unified factory creation
@@ -153,69 +150,6 @@ func detailsTab(kind, endpoint, schemaJSON string, keysOrder [][]string) map[str
}),
paramsList,
}
if kind == "VirtualPrivateCloud" {
rightColStack = append(rightColStack,
antdFlexVertical("vpc-subnets-block", 4, []any{
antdText("vpc-subnets-label", true, "Subnets", nil),
map[string]any{
"type": "EnrichedTable",
"data": map[string]any{
"id": "vpc-subnets-table",
"baseprefix": "/openapi-ui",
"clusterNamePartOfUrl": "{2}",
"customizationId": "virtualprivatecloud-subnets",
"fetchUrl": "/api/clusters/{2}/k8s/api/v1/namespaces/{3}/configmaps",
"fieldSelector": map[string]any{
"metadata.name": "virtualprivatecloud-{6}-subnets",
},
"pathToItems": []any{"items"},
},
},
}),
)
}
if kind == "Info" {
rightColStack = append(rightColStack,
antdFlexVertical("resource-quotas-block", 4, []any{
antdText("resource-quotas-label", true, "Resource Quotas", map[string]any{
"fontSize": float64(20),
"marginBottom": float64(12),
}),
map[string]any{
"type": "EnrichedTable",
"data": map[string]any{
"id": "resource-quotas-table",
"baseprefix": "/openapi-ui",
"clusterNamePartOfUrl": "{2}",
"customizationId": "factory-resource-quotas",
"fetchUrl": "/api/clusters/{2}/k8s/api/v1/namespaces/{3}/resourcequotas",
"pathToItems": []any{`items`},
},
},
}),
)
}
if kind == "Tenant" {
rightColStack = append(rightColStack,
antdFlexVertical("resource-quotas-block", 4, []any{
antdText("resource-quotas-label", true, "Resource Quotas", map[string]any{
"fontSize": float64(20),
"marginBottom": float64(12),
}),
map[string]any{
"type": "EnrichedTable",
"data": map[string]any{
"id": "resource-quotas-table",
"baseprefix": "/openapi-ui",
"clusterNamePartOfUrl": "{2}",
"customizationId": "factory-resource-quotas",
"fetchUrl": "/api/clusters/{2}/k8s/api/v1/namespaces/{3}/resourcequotas",
"pathToItems": []any{`items`},
},
},
}),
)
}
return map[string]any{
"key": "details",
@@ -397,36 +331,6 @@ func yamlTab(plural string) map[string]any {
}
}
func vncTabPrefix(kind string) (string, bool) {
switch kind {
case "VirtualMachine":
return "virtual-machine", true
case "VMInstance":
return "vm-instance", true
default:
return "", false
}
}
func vncTab(prefix string) map[string]any {
return map[string]any{
"key": "vnc",
"label": "VNC",
"children": []any{
map[string]any{
"type": "VMVNC",
"data": map[string]any{
"id": "vm-vnc",
"cluster": "{2}",
"namespace": "{reqsJsonPath[0]['.metadata.namespace']['-']}",
"substractHeight": float64(400),
"vmName": fmt.Sprintf("%s-{reqsJsonPath[0]['.metadata.name']['-']}", prefix),
},
},
},
}
}
// ---------------- OpenAPI → Right column ----------------
func buildOpenAPIParamsBlocks(schemaJSON string, keysOrder [][]string) []any {

View File

@@ -134,7 +134,7 @@ func CreateAllCustomColumnsOverrides() []*dashboardv1alpha1.CustomColumnsOverrid
createCustomColumnsOverride("factory-details-v1.services", []any{
createCustomColumnWithSpecificColor("Name", "Service", "", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/kube-service-details/{reqsJsonPath[0]['.metadata.name']['-']}"),
createStringColumn("ClusterIP", ".spec.clusterIP"),
createStringColumn("LoadbalancerIP", ".status.loadBalancer.ingress[0].ip"),
createStringColumn("LoadbalancerIP", ".spec.loadBalancerIP"),
createTimestampColumn("Created", ".metadata.creationTimestamp"),
}),
@@ -182,21 +182,6 @@ func CreateAllCustomColumnsOverrides() []*dashboardv1alpha1.CustomColumnsOverrid
createTimestampColumn("Created", ".metadata.creationTimestamp"),
}),
// Virtual private cloud subnets
createCustomColumnsOverride("virtualprivatecloud-subnets", []any{
createFlatMapColumn("Data", ".data"),
createStringColumn("Subnet Parameters", "_flatMapData_Key"),
createStringColumn("Values", "_flatMapData_Value"),
}),
// Factory resource quotas
createCustomColumnsOverride("factory-resource-quotas", []any{
createFlatMapColumn("Data", ".spec.hard"),
createStringColumn("Resource", "_flatMapData_Key"),
createStringColumn("Hard", "_flatMapData_Value"),
createStringColumn("Used", ".status.used['{_flatMapData_Key}']"),
}),
// Factory ingress details rules
createCustomColumnsOverride("factory-kube-ingress-details-rules", []any{
createStringColumn("Host", ".host"),
@@ -1128,7 +1113,7 @@ func CreateAllFactories() []*dashboardv1alpha1.Factory {
"clusterNamePartOfUrl": "{2}",
"customizationId": "factory-node-details-/v1/pods",
"fetchUrl": "/api/clusters/{2}/k8s/api/v1/namespaces/{3}/pods",
"labelSelectorFull": map[string]any{
"labelsSelectorFull": map[string]any{
"pathToLabels": ".spec.selector",
"reqIndex": 0,
},

View File

@@ -102,22 +102,6 @@ func antdFlex(id string, gap float64, children []any) map[string]any {
}
}
func antdFlexSpaceBetween(id string, children []any) map[string]any {
if id == "" {
id = generateContainerID("auto", "flex")
}
return map[string]any{
"type": "antdFlex",
"data": map[string]any{
"id": id,
"align": "center",
"justify": "space-between",
},
"children": children,
}
}
func antdFlexVertical(id string, gap float64, children []any) map[string]any {
// Auto-generate ID if not provided
if id == "" {

View File

@@ -237,16 +237,9 @@ func createUnifiedFactory(config UnifiedResourceConfig, tabs []any, urlsToFetch
"lineHeight": "24px",
})
header := antdFlexSpaceBetween(generateContainerID("header", "row"), []any{
antdFlex(generateContainerID("header", "title-text"), float64(6), []any{
badge,
nameText,
}),
antdLink(generateLinkID("header", "edit"),
"Edit",
fmt.Sprintf("/openapi-ui/{2}/{3}/forms/apis/{reqsJsonPath[0]['.apiVersion']['-']}/%s/{reqsJsonPath[0]['.metadata.name']['-']}",
config.Plural),
),
header := antdFlex(generateContainerID("header", "row"), float64(6), []any{
badge,
nameText,
})
// Add marginBottom style to header

View File

@@ -0,0 +1,140 @@
package controller
import (
"context"
"crypto/sha256"
"encoding/hex"
"fmt"
"sort"
"time"
helmv2 "github.com/fluxcd/helm-controller/api/v2"
corev1 "k8s.io/api/core/v1"
kerrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/event"
"sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/predicate"
)
type CozystackConfigReconciler struct {
client.Client
Scheme *runtime.Scheme
}
var configMapNames = []string{"cozystack", "cozystack-branding", "cozystack-scheduling"}
const configMapNamespace = "cozy-system"
const digestAnnotation = "cozystack.io/cozy-config-digest"
const forceReconcileKey = "reconcile.fluxcd.io/forceAt"
const requestedAt = "reconcile.fluxcd.io/requestedAt"
func (r *CozystackConfigReconciler) Reconcile(ctx context.Context, _ ctrl.Request) (ctrl.Result, error) {
log := log.FromContext(ctx)
time.Sleep(2 * time.Second)
digest, err := r.computeDigest(ctx)
if err != nil {
log.Error(err, "failed to compute config digest")
return ctrl.Result{}, nil
}
var helmList helmv2.HelmReleaseList
if err := r.List(ctx, &helmList); err != nil {
return ctrl.Result{}, fmt.Errorf("failed to list HelmReleases: %w", err)
}
now := time.Now().Format(time.RFC3339Nano)
updated := 0
for _, hr := range helmList.Items {
isSystemApp := hr.Labels["cozystack.io/system-app"] == "true"
isTenantRoot := hr.Namespace == "tenant-root" && hr.Name == "tenant-root"
if !isSystemApp && !isTenantRoot {
continue
}
patchTarget := hr.DeepCopy()
if hr.Annotations == nil {
hr.Annotations = map[string]string{}
}
if hr.Annotations[digestAnnotation] == digest {
continue
}
patchTarget.Annotations[digestAnnotation] = digest
patchTarget.Annotations[forceReconcileKey] = now
patchTarget.Annotations[requestedAt] = now
patch := client.MergeFrom(hr.DeepCopy())
if err := r.Patch(ctx, patchTarget, patch); err != nil {
log.Error(err, "failed to patch HelmRelease", "name", hr.Name, "namespace", hr.Namespace)
continue
}
updated++
log.Info("patched HelmRelease with new config digest", "name", hr.Name, "namespace", hr.Namespace)
}
log.Info("finished reconciliation", "updatedHelmReleases", updated)
return ctrl.Result{}, nil
}
func (r *CozystackConfigReconciler) computeDigest(ctx context.Context) (string, error) {
hash := sha256.New()
for _, name := range configMapNames {
var cm corev1.ConfigMap
err := r.Get(ctx, client.ObjectKey{Namespace: configMapNamespace, Name: name}, &cm)
if err != nil {
if kerrors.IsNotFound(err) {
continue // ignore missing
}
return "", err
}
// Sort keys for consistent hashing
var keys []string
for k := range cm.Data {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
v := cm.Data[k]
fmt.Fprintf(hash, "%s:%s=%s\n", name, k, v)
}
}
return hex.EncodeToString(hash.Sum(nil)), nil
}
func (r *CozystackConfigReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
WithEventFilter(predicate.Funcs{
UpdateFunc: func(e event.UpdateEvent) bool {
cm, ok := e.ObjectNew.(*corev1.ConfigMap)
return ok && cm.Namespace == configMapNamespace && contains(configMapNames, cm.Name)
},
CreateFunc: func(e event.CreateEvent) bool {
cm, ok := e.Object.(*corev1.ConfigMap)
return ok && cm.Namespace == configMapNamespace && contains(configMapNames, cm.Name)
},
DeleteFunc: func(e event.DeleteEvent) bool {
cm, ok := e.Object.(*corev1.ConfigMap)
return ok && cm.Namespace == configMapNamespace && contains(configMapNames, cm.Name)
},
}).
For(&corev1.ConfigMap{}).
Complete(r)
}
func contains(slice []string, val string) bool {
for _, s := range slice {
if s == val {
return true
}
}
return false
}

View File

@@ -0,0 +1,159 @@
package controller
import (
"context"
"fmt"
"strings"
"time"
e "errors"
helmv2 "github.com/fluxcd/helm-controller/api/v2"
"gopkg.in/yaml.v2"
corev1 "k8s.io/api/core/v1"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/log"
)
type TenantHelmReconciler struct {
client.Client
Scheme *runtime.Scheme
}
func (r *TenantHelmReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
logger := log.FromContext(ctx)
time.Sleep(2 * time.Second)
hr := &helmv2.HelmRelease{}
if err := r.Get(ctx, req.NamespacedName, hr); err != nil {
if errors.IsNotFound(err) {
return ctrl.Result{}, nil
}
logger.Error(err, "unable to fetch HelmRelease")
return ctrl.Result{}, err
}
if !strings.HasPrefix(hr.Name, "tenant-") {
return ctrl.Result{}, nil
}
if len(hr.Status.Conditions) == 0 || hr.Status.Conditions[0].Type != "Ready" {
return ctrl.Result{}, nil
}
if len(hr.Status.History) == 0 {
logger.Info("no history in HelmRelease status", "name", hr.Name)
return ctrl.Result{}, nil
}
if hr.Status.History[0].Status != "deployed" {
return ctrl.Result{}, nil
}
newDigest := hr.Status.History[0].Digest
var hrList helmv2.HelmReleaseList
childNamespace := getChildNamespace(hr.Namespace, hr.Name)
if childNamespace == "tenant-root" && hr.Name == "tenant-root" {
if hr.Spec.Values == nil {
logger.Error(e.New("hr.Spec.Values is nil"), "cant annotate tenant-root ns")
return ctrl.Result{}, nil
}
err := annotateTenantRootNs(*hr.Spec.Values, r.Client)
if err != nil {
logger.Error(err, "cant annotate tenant-root ns")
return ctrl.Result{}, nil
}
logger.Info("namespace 'tenant-root' annotated")
}
if err := r.List(ctx, &hrList, client.InNamespace(childNamespace)); err != nil {
logger.Error(err, "unable to list HelmReleases in namespace", "namespace", hr.Name)
return ctrl.Result{}, err
}
for _, item := range hrList.Items {
if item.Name == hr.Name {
continue
}
oldDigest := item.GetAnnotations()["cozystack.io/tenant-config-digest"]
if oldDigest == newDigest {
continue
}
patchTarget := item.DeepCopy()
if patchTarget.Annotations == nil {
patchTarget.Annotations = map[string]string{}
}
ts := time.Now().Format(time.RFC3339Nano)
patchTarget.Annotations["cozystack.io/tenant-config-digest"] = newDigest
patchTarget.Annotations["reconcile.fluxcd.io/forceAt"] = ts
patchTarget.Annotations["reconcile.fluxcd.io/requestedAt"] = ts
patch := client.MergeFrom(item.DeepCopy())
if err := r.Patch(ctx, patchTarget, patch); err != nil {
logger.Error(err, "failed to patch HelmRelease", "name", patchTarget.Name)
continue
}
logger.Info("patched HelmRelease with new digest", "name", patchTarget.Name, "digest", newDigest, "version", hr.Status.History[0].Version)
}
return ctrl.Result{}, nil
}
func (r *TenantHelmReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&helmv2.HelmRelease{}).
Complete(r)
}
func getChildNamespace(currentNamespace, hrName string) string {
tenantName := strings.TrimPrefix(hrName, "tenant-")
switch {
case currentNamespace == "tenant-root" && hrName == "tenant-root":
// 1) root tenant inside root namespace
return "tenant-root"
case currentNamespace == "tenant-root":
// 2) any other tenant in root namespace
return fmt.Sprintf("tenant-%s", tenantName)
default:
// 3) tenant in a dedicated namespace
return fmt.Sprintf("%s-%s", currentNamespace, tenantName)
}
}
func annotateTenantRootNs(values apiextensionsv1.JSON, c client.Client) error {
var data map[string]interface{}
if err := yaml.Unmarshal(values.Raw, &data); err != nil {
return fmt.Errorf("failed to parse HelmRelease values: %w", err)
}
host, ok := data["host"].(string)
if !ok || host == "" {
return fmt.Errorf("host field not found or not a string")
}
var ns corev1.Namespace
if err := c.Get(context.TODO(), client.ObjectKey{Name: "tenant-root"}, &ns); err != nil {
return fmt.Errorf("failed to get namespace tenant-root: %w", err)
}
if ns.Annotations == nil {
ns.Annotations = map[string]string{}
}
ns.Annotations["namespace.cozystack.io/host"] = host
if err := c.Update(context.TODO(), &ns); err != nil {
return fmt.Errorf("failed to update namespace: %w", err)
}
return nil
}

View File

@@ -467,8 +467,5 @@ func (r *WorkloadMonitorReconciler) getWorkloadMetadata(obj client.Object) map[s
if instanceType, ok := annotations["kubevirt.io/cluster-instancetype-name"]; ok {
labels["workloads.cozystack.io/kubevirt-vmi-instance-type"] = instanceType
}
if instanceProfile, ok := annotations["kubevirt.io/cluster-instanceprofile-name"]; ok {
labels["workloads.cozystack.io/kubevirt-vmi-instance-profile"] = instanceProfile
}
return labels
}

View File

@@ -2,72 +2,49 @@ package lineagecontrollerwebhook
import (
"fmt"
"strings"
cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1"
helmv2 "github.com/fluxcd/helm-controller/api/v2"
)
type chartRef struct {
repo string
chart string
}
type appRef struct {
group string
kind string
}
type runtimeConfig struct {
appCRDMap map[appRef]*cozyv1alpha1.CozystackResourceDefinition
chartAppMap map[chartRef]*cozyv1alpha1.CozystackResourceDefinition
appCRDMap map[appRef]*cozyv1alpha1.CozystackResourceDefinition
}
func (l *LineageControllerWebhook) initConfig() {
l.initOnce.Do(func() {
if l.config.Load() == nil {
l.config.Store(&runtimeConfig{
appCRDMap: make(map[appRef]*cozyv1alpha1.CozystackResourceDefinition),
chartAppMap: make(map[chartRef]*cozyv1alpha1.CozystackResourceDefinition),
appCRDMap: make(map[appRef]*cozyv1alpha1.CozystackResourceDefinition),
})
}
})
}
// getApplicationLabel safely extracts an application label from HelmRelease
func getApplicationLabel(hr *helmv2.HelmRelease, key string) (string, error) {
if hr.Labels == nil {
return "", fmt.Errorf("cannot map helm release %s/%s to dynamic app: labels are nil", hr.Namespace, hr.Name)
}
val, ok := hr.Labels[key]
if !ok {
return "", fmt.Errorf("cannot map helm release %s/%s to dynamic app: missing %s label", hr.Namespace, hr.Name, key)
}
return val, nil
}
func (l *LineageControllerWebhook) Map(hr *helmv2.HelmRelease) (string, string, string, error) {
// Extract application metadata from labels
appKind, err := getApplicationLabel(hr, "apps.cozystack.io/application.kind")
if err != nil {
return "", "", "", err
cfg, ok := l.config.Load().(*runtimeConfig)
if !ok {
return "", "", "", fmt.Errorf("failed to load chart-app mapping from config")
}
appGroup, err := getApplicationLabel(hr, "apps.cozystack.io/application.group")
if err != nil {
return "", "", "", err
if hr.Spec.Chart == nil {
return "", "", "", fmt.Errorf("cannot map helm release %s/%s to dynamic app", hr.Namespace, hr.Name)
}
appName, err := getApplicationLabel(hr, "apps.cozystack.io/application.name")
if err != nil {
return "", "", "", err
s := hr.Spec.Chart.Spec
val, ok := cfg.chartAppMap[chartRef{s.SourceRef.Name, s.Chart}]
if !ok {
return "", "", "", fmt.Errorf("cannot map helm release %s/%s to dynamic app", hr.Namespace, hr.Name)
}
// Construct API version from group
apiVersion := fmt.Sprintf("%s/v1alpha1", appGroup)
// Extract prefix from HelmRelease name by removing the application name
// HelmRelease name format: <prefix><application-name>
prefix := strings.TrimSuffix(hr.Name, appName)
// Validate the derived prefix
// This ensures correctness when appName appears multiple times in hr.Name
if prefix+appName != hr.Name {
return "", "", "", fmt.Errorf("cannot derive prefix from helm release %s/%s: name does not end with application name %s", hr.Namespace, hr.Name, appName)
}
return apiVersion, appKind, prefix, nil
return "apps.cozystack.io/v1alpha1", val.Spec.Application.Kind, val.Spec.Release.Prefix, nil
}

View File

@@ -24,15 +24,25 @@ func (c *LineageControllerWebhook) Reconcile(ctx context.Context, req ctrl.Reque
return ctrl.Result{}, err
}
cfg := &runtimeConfig{
appCRDMap: make(map[appRef]*cozyv1alpha1.CozystackResourceDefinition),
chartAppMap: make(map[chartRef]*cozyv1alpha1.CozystackResourceDefinition),
appCRDMap: make(map[appRef]*cozyv1alpha1.CozystackResourceDefinition),
}
for _, crd := range crds.Items {
chRef := chartRef{
crd.Spec.Release.Chart.SourceRef.Name,
crd.Spec.Release.Chart.Name,
}
appRef := appRef{
"apps.cozystack.io",
crd.Spec.Application.Kind,
}
newRef := crd
if _, exists := cfg.chartAppMap[chRef]; exists {
l.Info("duplicate chart mapping detected; ignoring subsequent entry", "key", chRef)
} else {
cfg.chartAppMap[chRef] = &newRef
}
if _, exists := cfg.appCRDMap[appRef]; exists {
l.Info("duplicate app mapping detected; ignoring subsequent entry", "key", appRef)
} else {

View File

@@ -1,4 +1,5 @@
{{- $seaweedfs := .Values._namespace.seaweedfs }}
{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }}
{{- $seaweedfs := index $myNS.metadata.annotations "namespace.cozystack.io/seaweedfs" }}
apiVersion: objectstorage.k8s.io/v1alpha1
kind: BucketClaim
metadata:

View File

@@ -21,8 +21,5 @@ spec:
force: true
remediation:
retries: -1
valuesFrom:
- kind: Secret
name: cozystack-values
values:
bucketName: {{ .Release.Name }}

View File

@@ -23,53 +23,53 @@ For more details, read [Restic: Effective Backup from Stdin](https://blog.aenix.
### Common parameters
| Name | Description | Type | Value |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------ | ---------- | ------- |
| `replicas` | Number of ClickHouse replicas. | `int` | `2` |
| `shards` | Number of ClickHouse shards. | `int` | `1` |
| `resources` | Explicit CPU and memory configuration for each ClickHouse replica. When omitted, the preset defined in `resourcesPreset` is applied. | `object` | `{}` |
| `resources.cpu` | CPU available to each replica. | `quantity` | `""` |
| `resources.memory` | Memory (RAM) available to each replica. | `quantity` | `""` |
| `resourcesPreset` | Default sizing preset used when `resources` is omitted. | `string` | `small` |
| `size` | Persistent Volume Claim size available for application data. | `quantity` | `10Gi` |
| `storageClass` | StorageClass used to store the data. | `string` | `""` |
| Name | Description | Type | Value |
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------- | ----------- | ------- |
| `replicas` | Number of Clickhouse replicas | `int` | `2` |
| `shards` | Number of Clickhouse shards | `int` | `1` |
| `resources` | Explicit CPU and memory configuration for each Clickhouse replica. When left empty, the preset defined in `resourcesPreset` is applied. | `*object` | `null` |
| `resources.cpu` | CPU available to each replica | `*quantity` | `null` |
| `resources.memory` | Memory (RAM) available to each replica | `*quantity` | `null` |
| `resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`. | `string` | `small` |
| `size` | Persistent Volume Claim size, available for application data | `quantity` | `10Gi` |
| `storageClass` | StorageClass used to store the data | `string` | `""` |
### Application-specific parameters
| Name | Description | Type | Value |
| ---------------------- | ------------------------------------------------------------- | ------------------- | ------- |
| `logStorageSize` | Size of Persistent Volume for logs. | `quantity` | `2Gi` |
| `logTTL` | TTL (expiration time) for `query_log` and `query_thread_log`. | `int` | `15` |
| `users` | Users configuration map. | `map[string]object` | `{}` |
| `users[name].password` | Password for the user. | `string` | `""` |
| `users[name].readonly` | User is readonly (default: false). | `bool` | `false` |
| Name | Description | Type | Value |
| ---------------------- | ------------------------------------------------------------ | ------------------- | ------- |
| `logStorageSize` | Size of Persistent Volume for logs | `quantity` | `2Gi` |
| `logTTL` | TTL (expiration time) for `query_log` and `query_thread_log` | `int` | `15` |
| `users` | Users configuration | `map[string]object` | `{...}` |
| `users[name].password` | Password for the user | `*string` | `null` |
| `users[name].readonly` | User is `readonly`, default is `false`. | `*bool` | `null` |
### Backup parameters
| Name | Description | Type | Value |
| ------------------------ | ----------------------------------------------- | -------- | ------------------------------------------------------ |
| `backup` | Backup configuration. | `object` | `{}` |
| `backup.enabled` | Enable regular backups (default: false). | `bool` | `false` |
| `backup.s3Region` | AWS S3 region where backups are stored. | `string` | `us-east-1` |
| `backup.s3Bucket` | S3 bucket used for storing backups. | `string` | `s3.example.org/clickhouse-backups` |
| `backup.schedule` | Cron schedule for automated backups. | `string` | `0 2 * * *` |
| `backup.cleanupStrategy` | Retention strategy for cleaning up old backups. | `string` | `--keep-last=3 --keep-daily=3 --keep-within-weekly=1m` |
| `backup.s3AccessKey` | Access key for S3 authentication. | `string` | `<your-access-key>` |
| `backup.s3SecretKey` | Secret key for S3 authentication. | `string` | `<your-secret-key>` |
| `backup.resticPassword` | Password for Restic backup encryption. | `string` | `<password>` |
| Name | Description | Type | Value |
| ------------------------ | ---------------------------------------------- | -------- | ------------------------------------------------------ |
| `backup` | Backup configuration | `object` | `{}` |
| `backup.enabled` | Enable regular backups, default is `false` | `bool` | `false` |
| `backup.s3Region` | AWS S3 region where backups are stored | `string` | `us-east-1` |
| `backup.s3Bucket` | S3 bucket used for storing backups | `string` | `s3.example.org/clickhouse-backups` |
| `backup.schedule` | Cron schedule for automated backups | `string` | `0 2 * * *` |
| `backup.cleanupStrategy` | Retention strategy for cleaning up old backups | `string` | `--keep-last=3 --keep-daily=3 --keep-within-weekly=1m` |
| `backup.s3AccessKey` | Access key for S3, used for authentication | `string` | `<your-access-key>` |
| `backup.s3SecretKey` | Secret key for S3, used for authentication | `string` | `<your-secret-key>` |
| `backup.resticPassword` | Password for Restic backup encryption | `string` | `<password>` |
### ClickHouse Keeper parameters
### Clickhouse Keeper parameters
| Name | Description | Type | Value |
| ---------------------------------- | ------------------------------------------------------------ | ---------- | ------- |
| `clickhouseKeeper` | ClickHouse Keeper configuration. | `object` | `{}` |
| `clickhouseKeeper.enabled` | Deploy ClickHouse Keeper for cluster coordination. | `bool` | `true` |
| `clickhouseKeeper.size` | Persistent Volume Claim size available for application data. | `quantity` | `1Gi` |
| `clickhouseKeeper.resourcesPreset` | Default sizing preset. | `string` | `micro` |
| `clickhouseKeeper.replicas` | Number of Keeper replicas. | `int` | `3` |
| Name | Description | Type | Value |
| ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | ----------- | ------- |
| `clickhouseKeeper` | Clickhouse Keeper configuration | `*object` | `null` |
| `clickhouseKeeper.enabled` | Deploy ClickHouse Keeper for cluster coordination | `*bool` | `true` |
| `clickhouseKeeper.size` | Persistent Volume Claim size, available for application data | `*quantity` | `1Gi` |
| `clickhouseKeeper.resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`. | `string` | `micro` |
| `clickhouseKeeper.replicas` | Number of Keeper replicas | `*int` | `3` |
## Parameter examples and reference

View File

@@ -1,4 +1,5 @@
{{- $clusterDomain := (index .Values._cluster "cluster-domain") | default "cozy.local" }}
{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }}
{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }}
{{- if .Values.clickhouseKeeper.enabled }}
apiVersion: "clickhouse-keeper.altinity.com/v1"

View File

@@ -1,4 +1,5 @@
{{- $clusterDomain := (index .Values._cluster "cluster-domain") | default "cozy.local" }}
{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }}
{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }}
{{- $existingSecret := lookup "v1" "Secret" .Release.Namespace (printf "%s-credentials" .Release.Name) }}
{{- $passwords := dict }}
{{- $users := .Values.users }}

View File

@@ -3,7 +3,7 @@
"type": "object",
"properties": {
"backup": {
"description": "Backup configuration.",
"description": "Backup configuration",
"type": "object",
"default": {},
"required": [
@@ -18,64 +18,67 @@
],
"properties": {
"cleanupStrategy": {
"description": "Retention strategy for cleaning up old backups.",
"description": "Retention strategy for cleaning up old backups",
"type": "string",
"default": "--keep-last=3 --keep-daily=3 --keep-within-weekly=1m"
},
"enabled": {
"description": "Enable regular backups (default: false).",
"description": "Enable regular backups, default is `false`",
"type": "boolean",
"default": false
},
"resticPassword": {
"description": "Password for Restic backup encryption.",
"description": "Password for Restic backup encryption",
"type": "string",
"default": "\u003cpassword\u003e"
},
"s3AccessKey": {
"description": "Access key for S3 authentication.",
"description": "Access key for S3, used for authentication",
"type": "string",
"default": "\u003cyour-access-key\u003e"
},
"s3Bucket": {
"description": "S3 bucket used for storing backups.",
"description": "S3 bucket used for storing backups",
"type": "string",
"default": "s3.example.org/clickhouse-backups"
},
"s3Region": {
"description": "AWS S3 region where backups are stored.",
"description": "AWS S3 region where backups are stored",
"type": "string",
"default": "us-east-1"
},
"s3SecretKey": {
"description": "Secret key for S3 authentication.",
"description": "Secret key for S3, used for authentication",
"type": "string",
"default": "\u003cyour-secret-key\u003e"
},
"schedule": {
"description": "Cron schedule for automated backups.",
"description": "Cron schedule for automated backups",
"type": "string",
"default": "0 2 * * *"
}
}
},
"clickhouseKeeper": {
"description": "ClickHouse Keeper configuration.",
"description": "Clickhouse Keeper configuration",
"type": "object",
"default": {},
"required": [
"resourcesPreset"
],
"properties": {
"enabled": {
"description": "Deploy ClickHouse Keeper for cluster coordination.",
"description": "Deploy ClickHouse Keeper for cluster coordination",
"type": "boolean",
"default": true
},
"replicas": {
"description": "Number of Keeper replicas.",
"description": "Number of Keeper replicas",
"type": "integer",
"default": 3
},
"resourcesPreset": {
"description": "Default sizing preset.",
"description": "Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`.",
"type": "string",
"default": "micro",
"enum": [
@@ -89,7 +92,7 @@
]
},
"size": {
"description": "Persistent Volume Claim size available for application data.",
"description": "Persistent Volume Claim size, available for application data",
"default": "1Gi",
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
"anyOf": [
@@ -105,7 +108,7 @@
}
},
"logStorageSize": {
"description": "Size of Persistent Volume for logs.",
"description": "Size of Persistent Volume for logs",
"default": "2Gi",
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
"anyOf": [
@@ -119,22 +122,22 @@
"x-kubernetes-int-or-string": true
},
"logTTL": {
"description": "TTL (expiration time) for `query_log` and `query_thread_log`.",
"description": "TTL (expiration time) for `query_log` and `query_thread_log`",
"type": "integer",
"default": 15
},
"replicas": {
"description": "Number of ClickHouse replicas.",
"description": "Number of Clickhouse replicas",
"type": "integer",
"default": 2
},
"resources": {
"description": "Explicit CPU and memory configuration for each ClickHouse replica. When omitted, the preset defined in `resourcesPreset` is applied.",
"description": "Explicit CPU and memory configuration for each Clickhouse replica. When left empty, the preset defined in `resourcesPreset` is applied.",
"type": "object",
"default": {},
"properties": {
"cpu": {
"description": "CPU available to each replica.",
"description": "CPU available to each replica",
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
"anyOf": [
{
@@ -147,7 +150,7 @@
"x-kubernetes-int-or-string": true
},
"memory": {
"description": "Memory (RAM) available to each replica.",
"description": "Memory (RAM) available to each replica",
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
"anyOf": [
{
@@ -162,7 +165,7 @@
}
},
"resourcesPreset": {
"description": "Default sizing preset used when `resources` is omitted.",
"description": "Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`.",
"type": "string",
"default": "small",
"enum": [
@@ -176,12 +179,12 @@
]
},
"shards": {
"description": "Number of ClickHouse shards.",
"description": "Number of Clickhouse shards",
"type": "integer",
"default": 1
},
"size": {
"description": "Persistent Volume Claim size available for application data.",
"description": "Persistent Volume Claim size, available for application data",
"default": "10Gi",
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
"anyOf": [
@@ -195,23 +198,22 @@
"x-kubernetes-int-or-string": true
},
"storageClass": {
"description": "StorageClass used to store the data.",
"type": "string",
"default": ""
"description": "StorageClass used to store the data",
"type": "string"
},
"users": {
"description": "Users configuration map.",
"description": "Users configuration",
"type": "object",
"default": {},
"additionalProperties": {
"type": "object",
"properties": {
"password": {
"description": "Password for the user.",
"description": "Password for the user",
"type": "string"
},
"readonly": {
"description": "User is readonly (default: false).",
"description": "User is `readonly`, default is `false`.",
"type": "boolean"
}
}

View File

@@ -1,54 +1,36 @@
##
## @section Common parameters
##
## @typedef {struct} Resources - Explicit CPU and memory configuration for each ClickHouse replica.
## @field {quantity} [cpu] - CPU available to each replica.
## @field {quantity} [memory] - Memory (RAM) available to each replica.
## @enum {string} ResourcesPreset - Default sizing preset.
## @value nano
## @value micro
## @value small
## @value medium
## @value large
## @value xlarge
## @value 2xlarge
## @param {int} replicas - Number of ClickHouse replicas.
## @param replicas {int} Number of Clickhouse replicas
replicas: 2
## @param {int} shards - Number of ClickHouse shards.
## @param shards {int} Number of Clickhouse shards
shards: 1
## @param {Resources} [resources] - Explicit CPU and memory configuration for each ClickHouse replica. When omitted, the preset defined in `resourcesPreset` is applied.
## @param resources {*resources} Explicit CPU and memory configuration for each Clickhouse replica. When left empty, the preset defined in `resourcesPreset` is applied.
## @field resources.cpu {*quantity} CPU available to each replica
## @field resources.memory {*quantity} Memory (RAM) available to each replica
# resources:
# cpu: 4000m
# memory: 4Gi
resources: {}
## @param {ResourcesPreset} resourcesPreset="small" - Default sizing preset used when `resources` is omitted.
## @param resourcesPreset {string enum:"nano,micro,small,medium,large,xlarge,2xlarge"} Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`.
resourcesPreset: "small"
## @param {quantity} size - Persistent Volume Claim size available for application data.
## @param size {quantity} Persistent Volume Claim size, available for application data
size: 10Gi
## @param {string} storageClass - StorageClass used to store the data.
## @param storageClass {string} StorageClass used to store the data
storageClass: ""
##
## @section Application-specific parameters
##
## @param {quantity} logStorageSize - Size of Persistent Volume for logs.
## @param logStorageSize {quantity} Size of Persistent Volume for logs
logStorageSize: 2Gi
## @param {int} logTTL - TTL (expiration time) for `query_log` and `query_thread_log`.
## @param logTTL {int} TTL (expiration time) for `query_log` and `query_thread_log`
logTTL: 15
## @typedef {struct} User - User configuration.
## @field {string} [password] - Password for the user.
## @field {bool} [readonly] - User is readonly (default: false).
## @param {map[string]User} users - Users configuration map.
users: {}
## @param users {map[string]user} Users configuration
## @field user.password {*string} Password for the user
## @field user.readonly {*bool} User is `readonly`, default is `false`.
## Example:
## users:
## user1:
@@ -57,22 +39,20 @@ users: {}
## readonly: true
## password: hackme
##
users: {}
##
## @section Backup parameters
##
## @typedef {struct} Backup - Backup configuration.
## @field {bool} enabled - Enable regular backups (default: false).
## @field {string} s3Region - AWS S3 region where backups are stored.
## @field {string} s3Bucket - S3 bucket used for storing backups.
## @field {string} schedule - Cron schedule for automated backups.
## @field {string} cleanupStrategy - Retention strategy for cleaning up old backups.
## @field {string} s3AccessKey - Access key for S3 authentication.
## @field {string} s3SecretKey - Secret key for S3 authentication.
## @field {string} resticPassword - Password for Restic backup encryption.
## @param {Backup} backup - Backup configuration.
## @param backup {backup} Backup configuration
## @field backup.enabled {bool} Enable regular backups, default is `false`
## @field backup.s3Region {string} AWS S3 region where backups are stored
## @field backup.s3Bucket {string} S3 bucket used for storing backups
## @field backup.schedule {string} Cron schedule for automated backups
## @field backup.cleanupStrategy {string} Retention strategy for cleaning up old backups
## @field backup.s3AccessKey {string} Access key for S3, used for authentication
## @field backup.s3SecretKey {string} Secret key for S3, used for authentication
## @field backup.resticPassword {string} Password for Restic backup encryption
backup:
enabled: false
s3Region: us-east-1
@@ -83,17 +63,13 @@ backup:
s3SecretKey: "<your-secret-key>"
resticPassword: "<password>"
##
## @section ClickHouse Keeper parameters
##
## @typedef {struct} ClickHouseKeeper - ClickHouse Keeper configuration.
## @field {bool} [enabled] - Deploy ClickHouse Keeper for cluster coordination.
## @field {quantity} [size] - Persistent Volume Claim size available for application data.
## @field {ResourcesPreset} [resourcesPreset] - Default sizing preset.
## @field {int} [replicas] - Number of Keeper replicas.
## @param {ClickHouseKeeper} clickhouseKeeper - ClickHouse Keeper configuration.
## @section Clickhouse Keeper parameters
## @param clickhouseKeeper {*clickhouseKeeper} Clickhouse Keeper configuration
## @field clickhouseKeeper.enabled {*bool} Deploy ClickHouse Keeper for cluster coordination
## @field clickhouseKeeper.size {*quantity} Persistent Volume Claim size, available for application data
## @field clickhouseKeeper.resourcesPreset {string enum:"nano,micro,small,medium,large,xlarge,2xlarge"} Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`.
## @field clickhouseKeeper.replicas {*int} Number of Keeper replicas
clickhouseKeeper:
enabled: true
size: 1Gi

View File

@@ -8,51 +8,51 @@ Internally, FerretDB service is backed by Postgres.
### Common parameters
| Name | Description | Type | Value |
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------- | ---------- | ------- |
| `replicas` | Number of replicas. | `int` | `2` |
| `resources` | Explicit CPU and memory configuration for each FerretDB replica. When omitted, the preset defined in `resourcesPreset` is applied. | `object` | `{}` |
| `resources.cpu` | CPU available to each replica. | `quantity` | `""` |
| `resources.memory` | Memory (RAM) available to each replica. | `quantity` | `""` |
| `resourcesPreset` | Default sizing preset used when `resources` is omitted. | `string` | `micro` |
| `size` | Persistent Volume Claim size available for application data. | `quantity` | `10Gi` |
| `storageClass` | StorageClass used to store the data. | `string` | `""` |
| `external` | Enable external access from outside the cluster. | `bool` | `false` |
| Name | Description | Type | Value |
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------- | ----------- | ------- |
| `replicas` | Number of replicas | `int` | `2` |
| `resources` | Explicit CPU and memory configuration for each FerretDB replica. When left empty, the preset defined in `resourcesPreset` is applied. | `*object` | `null` |
| `resources.cpu` | CPU available to each replica | `*quantity` | `null` |
| `resources.memory` | Memory (RAM) available to each replica | `*quantity` | `null` |
| `resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`. | `string` | `micro` |
| `size` | Persistent Volume Claim size, available for application data | `quantity` | `10Gi` |
| `storageClass` | StorageClass used to store the data | `string` | `""` |
| `external` | Enable external access from outside the cluster | `bool` | `false` |
### Application-specific parameters
| Name | Description | Type | Value |
| ------------------------ | ---------------------------------------------------------------------------------- | ------------------- | ----- |
| `quorum` | Configuration for quorum-based synchronous replication. | `object` | `{}` |
| `quorum.minSyncReplicas` | Minimum number of synchronous replicas required for commit. | `int` | `0` |
| `quorum.maxSyncReplicas` | Maximum number of synchronous replicas allowed (must be less than total replicas). | `int` | `0` |
| `users` | Users configuration map. | `map[string]object` | `{}` |
| `users[name].password` | Password for the user. | `string` | `""` |
| Name | Description | Type | Value |
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------- | ------------------- | ------- |
| `quorum` | Configuration for the quorum-based synchronous replication | `object` | `{}` |
| `quorum.minSyncReplicas` | Minimum number of synchronous replicas that must acknowledge a transaction before it is considered committed | `int` | `0` |
| `quorum.maxSyncReplicas` | Maximum number of synchronous replicas that can acknowledge a transaction (must be lower than the total number of replicas) | `int` | `0` |
| `users` | Users configuration | `map[string]object` | `{...}` |
| `users[name].password` | Password for the user | `*string` | `null` |
### Backup parameters
| Name | Description | Type | Value |
| ------------------------ | ------------------------------------------------------------ | -------- | ----------------------------------- |
| `backup` | Backup configuration. | `object` | `{}` |
| `backup.enabled` | Enable regular backups (default: false). | `bool` | `false` |
| `backup.schedule` | Cron schedule for automated backups. | `string` | `0 2 * * * *` |
| `backup.retentionPolicy` | Retention policy. | `string` | `30d` |
| `backup.endpointURL` | S3 endpoint URL for uploads. | `string` | `http://minio-gateway-service:9000` |
| `backup.destinationPath` | Path to store the backup (e.g. s3://bucket/path/to/folder/). | `string` | `s3://bucket/path/to/folder/` |
| `backup.s3AccessKey` | Access key for S3 authentication. | `string` | `<your-access-key>` |
| `backup.s3SecretKey` | Secret key for S3 authentication. | `string` | `<your-secret-key>` |
| Name | Description | Type | Value |
| ------------------------ | ---------------------------------------------------------- | -------- | ----------------------------------- |
| `backup` | Backup configuration | `object` | `{}` |
| `backup.enabled` | Enable regular backups, default is `false`. | `bool` | `false` |
| `backup.schedule` | Cron schedule for automated backups | `string` | `0 2 * * * *` |
| `backup.retentionPolicy` | Retention policy | `string` | `30d` |
| `backup.endpointURL` | S3 Endpoint used to upload data to the cloud | `string` | `http://minio-gateway-service:9000` |
| `backup.destinationPath` | Path to store the backup (i.e. s3://bucket/path/to/folder) | `string` | `s3://bucket/path/to/folder/` |
| `backup.s3AccessKey` | Access key for S3, used for authentication | `string` | `<your-access-key>` |
| `backup.s3SecretKey` | Secret key for S3, used for authentication | `string` | `<your-secret-key>` |
### Bootstrap (recovery) parameters
| Name | Description | Type | Value |
| ------------------------ | ------------------------------------------------------------------- | -------- | ------- |
| `bootstrap` | Bootstrap configuration. | `object` | `{}` |
| `bootstrap.enabled` | Restore database cluster from a backup. | `bool` | `false` |
| `bootstrap.recoveryTime` | Timestamp (RFC3339) for point-in-time recovery; empty means latest. | `string` | `""` |
| `bootstrap.oldName` | Name of database cluster before deletion. | `string` | `""` |
| Name | Description | Type | Value |
| ------------------------ | --------------------------------------------------------------------------------------------------------------------- | --------- | ------- |
| `bootstrap` | Bootstrap (recovery) configuration | `object` | `{}` |
| `bootstrap.enabled` | Restore database cluster from a backup | `*bool` | `false` |
| `bootstrap.recoveryTime` | Timestamp (PITR) up to which recovery will proceed, expressed in RFC 3339 format. If left empty, will restore latest. | `*string` | `""` |
| `bootstrap.oldName` | Name of database cluster before deleting | `*string` | `""` |
## Parameter examples and reference

View File

@@ -50,8 +50,9 @@ spec:
postgresUID: 999
postgresGID: 999
enableSuperuserAccess: true
{{- if .Values._cluster.scheduling }}
{{- $rawConstraints := get .Values._cluster.scheduling "globalAppTopologySpreadConstraints" }}
{{- $configMap := lookup "v1" "ConfigMap" "cozy-system" "cozystack-scheduling" }}
{{- if $configMap }}
{{- $rawConstraints := get $configMap.data "globalAppTopologySpreadConstraints" }}
{{- if $rawConstraints }}
{{- $rawConstraints | fromYaml | toYaml | nindent 2 }}
labelSelector:

View File

@@ -3,7 +3,7 @@
"type": "object",
"properties": {
"backup": {
"description": "Backup configuration.",
"description": "Backup configuration",
"type": "object",
"default": {},
"required": [
@@ -17,71 +17,69 @@
],
"properties": {
"destinationPath": {
"description": "Path to store the backup (e.g. s3://bucket/path/to/folder/).",
"description": "Path to store the backup (i.e. s3://bucket/path/to/folder)",
"type": "string",
"default": "s3://bucket/path/to/folder/"
},
"enabled": {
"description": "Enable regular backups (default: false).",
"description": "Enable regular backups, default is `false`.",
"type": "boolean",
"default": false
},
"endpointURL": {
"description": "S3 endpoint URL for uploads.",
"description": "S3 Endpoint used to upload data to the cloud",
"type": "string",
"default": "http://minio-gateway-service:9000"
},
"retentionPolicy": {
"description": "Retention policy.",
"description": "Retention policy",
"type": "string",
"default": "30d"
},
"s3AccessKey": {
"description": "Access key for S3 authentication.",
"description": "Access key for S3, used for authentication",
"type": "string",
"default": "\u003cyour-access-key\u003e"
},
"s3SecretKey": {
"description": "Secret key for S3 authentication.",
"description": "Secret key for S3, used for authentication",
"type": "string",
"default": "\u003cyour-secret-key\u003e"
},
"schedule": {
"description": "Cron schedule for automated backups.",
"description": "Cron schedule for automated backups",
"type": "string",
"default": "0 2 * * * *"
}
}
},
"bootstrap": {
"description": "Bootstrap configuration.",
"description": "Bootstrap (recovery) configuration",
"type": "object",
"default": {},
"properties": {
"enabled": {
"description": "Restore database cluster from a backup.",
"description": "Restore database cluster from a backup",
"type": "boolean",
"default": false
},
"oldName": {
"description": "Name of database cluster before deletion.",
"type": "string",
"default": ""
"description": "Name of database cluster before deleting",
"type": "string"
},
"recoveryTime": {
"description": "Timestamp (RFC3339) for point-in-time recovery; empty means latest.",
"type": "string",
"default": ""
"description": "Timestamp (PITR) up to which recovery will proceed, expressed in RFC 3339 format. If left empty, will restore latest.",
"type": "string"
}
}
},
"external": {
"description": "Enable external access from outside the cluster.",
"description": "Enable external access from outside the cluster",
"type": "boolean",
"default": false
},
"quorum": {
"description": "Configuration for quorum-based synchronous replication.",
"description": "Configuration for the quorum-based synchronous replication",
"type": "object",
"default": {},
"required": [
@@ -90,29 +88,29 @@
],
"properties": {
"maxSyncReplicas": {
"description": "Maximum number of synchronous replicas allowed (must be less than total replicas).",
"description": "Maximum number of synchronous replicas that can acknowledge a transaction (must be lower than the total number of replicas)",
"type": "integer",
"default": 0
},
"minSyncReplicas": {
"description": "Minimum number of synchronous replicas required for commit.",
"description": "Minimum number of synchronous replicas that must acknowledge a transaction before it is considered committed",
"type": "integer",
"default": 0
}
}
},
"replicas": {
"description": "Number of replicas.",
"description": "Number of replicas",
"type": "integer",
"default": 2
},
"resources": {
"description": "Explicit CPU and memory configuration for each FerretDB replica. When omitted, the preset defined in `resourcesPreset` is applied.",
"description": "Explicit CPU and memory configuration for each FerretDB replica. When left empty, the preset defined in `resourcesPreset` is applied.",
"type": "object",
"default": {},
"properties": {
"cpu": {
"description": "CPU available to each replica.",
"description": "CPU available to each replica",
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
"anyOf": [
{
@@ -125,7 +123,7 @@
"x-kubernetes-int-or-string": true
},
"memory": {
"description": "Memory (RAM) available to each replica.",
"description": "Memory (RAM) available to each replica",
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
"anyOf": [
{
@@ -140,7 +138,7 @@
}
},
"resourcesPreset": {
"description": "Default sizing preset used when `resources` is omitted.",
"description": "Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`.",
"type": "string",
"default": "micro",
"enum": [
@@ -154,7 +152,7 @@
]
},
"size": {
"description": "Persistent Volume Claim size available for application data.",
"description": "Persistent Volume Claim size, available for application data",
"default": "10Gi",
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
"anyOf": [
@@ -168,19 +166,18 @@
"x-kubernetes-int-or-string": true
},
"storageClass": {
"description": "StorageClass used to store the data.",
"type": "string",
"default": ""
"description": "StorageClass used to store the data",
"type": "string"
},
"users": {
"description": "Users configuration map.",
"description": "Users configuration",
"type": "object",
"default": {},
"additionalProperties": {
"type": "object",
"properties": {
"password": {
"description": "Password for the user.",
"description": "Password for the user",
"type": "string"
}
}

View File

@@ -1,56 +1,35 @@
##
## @section Common parameters
##
## @typedef {struct} Resources - Explicit CPU and memory configuration for each FerretDB replica.
## @field {quantity} [cpu] - CPU available to each replica.
## @field {quantity} [memory] - Memory (RAM) available to each replica.
## @enum {string} ResourcesPreset - Default sizing preset.
## @value nano
## @value micro
## @value small
## @value medium
## @value large
## @value xlarge
## @value 2xlarge
## @param {int} replicas - Number of replicas.
## @param replicas {int} Number of replicas
replicas: 2
## @param {Resources} [resources] - Explicit CPU and memory configuration for each FerretDB replica. When omitted, the preset defined in `resourcesPreset` is applied.
## @param resources {*resources} Explicit CPU and memory configuration for each FerretDB replica. When left empty, the preset defined in `resourcesPreset` is applied.
## @field resources.cpu {*quantity} CPU available to each replica
## @field resources.memory {*quantity} Memory (RAM) available to each replica
# resources:
# cpu: 4000m
# memory: 4Gi
resources: {}
## @param {ResourcesPreset} resourcesPreset="micro" - Default sizing preset used when `resources` is omitted.
## @param resourcesPreset {string enum:"nano,micro,small,medium,large,xlarge,2xlarge"} Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`.
resourcesPreset: "micro"
## @param {quantity} size - Persistent Volume Claim size available for application data.
## @param size {quantity} Persistent Volume Claim size, available for application data
size: 10Gi
## @param {string} storageClass - StorageClass used to store the data.
## @param storageClass {string} StorageClass used to store the data
storageClass: ""
## @param {bool} external - Enable external access from outside the cluster.
## @param external {bool} Enable external access from outside the cluster
external: false
##
## @section Application-specific parameters
##
## @typedef {struct} Quorum - Configuration for quorum-based synchronous replication.
## @field {int} minSyncReplicas - Minimum number of synchronous replicas required for commit.
## @field {int} maxSyncReplicas - Maximum number of synchronous replicas allowed (must be less than total replicas).
## @param {Quorum} quorum - Configuration for quorum-based synchronous replication.
## @param quorum {quorum} Configuration for the quorum-based synchronous replication
## @field quorum.minSyncReplicas {int} Minimum number of synchronous replicas that must acknowledge a transaction before it is considered committed
## @field quorum.maxSyncReplicas {int} Maximum number of synchronous replicas that can acknowledge a transaction (must be lower than the total number of replicas)
quorum:
minSyncReplicas: 0
maxSyncReplicas: 0
## @typedef {struct} User - User configuration.
## @field {string} [password] - Password for the user.
## @param {map[string]User} users - Users configuration map.
users: {}
## @param users {map[string]user} Users configuration
## @field user.password {*string} Password for the user
## Example:
## users:
## user1:
@@ -58,21 +37,21 @@ users: {}
## user2:
## password: hackme
##
users: {}
##
## @section Backup parameters
##
## @typedef {struct} Backup - Backup configuration.
## @field {bool} enabled - Enable regular backups (default: false).
## @field {string} schedule - Cron schedule for automated backups.
## @field {string} retentionPolicy - Retention policy.
## @field {string} endpointURL - S3 endpoint URL for uploads.
## @field {string} destinationPath - Path to store the backup (e.g. s3://bucket/path/to/folder/).
## @field {string} s3AccessKey - Access key for S3 authentication.
## @field {string} s3SecretKey - Secret key for S3 authentication.
## @param {Backup} backup - Backup configuration.
## @param backup {backup} Backup configuration
## @field backup.enabled {bool} Enable regular backups, default is `false`.
## @field backup.schedule {string} Cron schedule for automated backups
## @field backup.retentionPolicy {string} Retention policy
## @field backup.endpointURL {string} S3 Endpoint used to upload data to the cloud
## @field backup.destinationPath {string} Path to store the backup (i.e. s3://bucket/path/to/folder)
## @field backup.s3AccessKey {string} Access key for S3, used for authentication
## @field backup.s3SecretKey {string} Secret key for S3, used for authentication
backup:
enabled: false
schedule: "0 2 * * * *"
@@ -82,17 +61,18 @@ backup:
s3AccessKey: "<your-access-key>"
s3SecretKey: "<your-secret-key>"
##
## @section Bootstrap (recovery) parameters
##
## @typedef {struct} Bootstrap - Bootstrap configuration for restoring a database cluster from a backup.
## @field {bool} [enabled] - Restore database cluster from a backup.
## @field {string} [recoveryTime] - Timestamp (RFC3339) for point-in-time recovery; empty means latest.
## @field {string} [oldName] - Name of database cluster before deletion.
## @param {Bootstrap} bootstrap - Bootstrap configuration.
## @param bootstrap {bootstrap} Bootstrap (recovery) configuration
## @field bootstrap.enabled {*bool} Restore database cluster from a backup
## @field bootstrap.recoveryTime {*string} Timestamp (PITR) up to which recovery will proceed, expressed in RFC 3339 format. If left empty, will restore latest.
## @field bootstrap.oldName {*string} Name of database cluster before deleting
##
bootstrap:
enabled: false
# example: 2020-11-26 15:22:00.00000+00
recoveryTime: ""
oldName: ""

View File

@@ -1 +0,0 @@
Makefile

View File

@@ -1,25 +0,0 @@
apiVersion: v2
name: foundationdb
description: Managed FoundationDB service
icon: /logos/foundationdb.svg
# A chart can be either an 'application' or a 'library' chart.
#
# Application charts are a collection of templates that can be packaged into versioned archives
# to be deployed.
#
# Library charts provide useful utilities or functions for the chart developer. They're included as
# a dependency of application charts to inject those utilities and functions into the rendering
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.1.0
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: "7.3.63"

View File

@@ -1,4 +0,0 @@
include ../../../scripts/package.mk
generate:
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md

View File

@@ -1,195 +0,0 @@
# FoundationDB
A managed FoundationDB service for Cozystack.
## Overview
FoundationDB is a distributed database designed to handle large volumes of structured data across clusters of commodity servers. It organizes data as an ordered key-value store and employs ACID transactions for all operations.
This package provides a managed FoundationDB cluster deployment using the FoundationDB Kubernetes Operator.
## Features
- **High Availability**: Multi-instance deployment with automatic failover
- **ACID Transactions**: Full ACID transaction support across the cluster
- **Scalable**: Easily scale storage and compute resources
- **Backup Integration**: Optional S3-compatible backup storage
- **Monitoring**: Built-in monitoring and alerting through WorkloadMonitor
- **Flexible Configuration**: Support for custom FoundationDB parameters
## Configuration
### Basic Configuration
```yaml
# Cluster process configuration
cluster:
version: "7.3.63"
processCounts:
storage: 3 # Number of storage processes (determines cluster size)
stateless: -1 # Automatically calculated
cluster_controller: 1
faultDomain:
key: "kubernetes.io/hostname"
valueFrom: "spec.nodeName"
```
### Storage
```yaml
storage:
size: "16Gi" # Storage size per instance
storageClass: "" # Storage class (optional)
```
### Resources
```yaml
# Use preset sizing
resourcesPreset: "medium" # small, medium, large, xlarge, 2xlarge
# Or custom resource configuration
resources:
cpu: "2000m"
memory: "4Gi"
```
### Backup (Optional)
```yaml
backup:
enabled: true
s3:
bucket: "my-fdb-backups"
endpoint: "https://s3.amazonaws.com"
region: "us-east-1"
credentials:
accessKeyId: "AKIA..."
secretAccessKey: "..."
retentionPolicy: "7d"
```
### Advanced Configuration
```yaml
# Custom FoundationDB parameters
customParameters:
- "knob_disable_posix_kernel_aio=1"
# Image type (unified is default and recommended for new deployments)
imageType: "unified"
# Enable automatic pod replacements
automaticReplacements: true
# Security context configuration
securityContext:
runAsUser: 4059
runAsGroup: 4059
```
## Prerequisites
- FoundationDB Operator must be installed in the cluster
- Sufficient storage and compute resources
- For backups: S3-compatible storage credentials
## Deployment
1. Install the FoundationDB operator (system package)
2. Deploy this application package with your desired configuration
3. The cluster will be automatically provisioned and configured
## Monitoring
This package includes WorkloadMonitor integration for cluster health monitoring and resource tracking. Monitoring can be disabled by setting:
```yaml
monitoring:
enabled: false
```
## Security
- All containers run with restricted security contexts
- No privilege escalation allowed
- Read-only root filesystem where possible
- Custom security context configurations supported
## Fault Tolerance
FoundationDB is designed for high availability:
- Automatic failure detection and recovery
- Data replication across instances
- Configurable fault domains for rack/zone awareness
- Transaction log redundancy
The included `WorkloadMonitor` is automatically configured based on the `cluster.redundancyMode` value. It sets the `minReplicas` property on the `WorkloadMonitor` resource to ensure the cluster's health status accurately reflects its fault tolerance level. The number of tolerated failures is as follows:
- `single`: 0 failures
- `double`: 1 failure
- `triple` and datacenter-aware modes: 2 failures
For example, with the default configuration (`redundancyMode: double` and 3 storage pods), `minReplicas` will be set to 2.
## Performance Considerations
- Use SSD storage for better performance
- Consider dedicating nodes for storage processes
- Monitor cluster metrics for optimization opportunities
- Scale storage and stateless processes based on workload
## Support
For issues related to FoundationDB itself, refer to the [FoundationDB documentation](https://apple.github.io/foundationdb/).
For Cozystack-specific issues, consult the Cozystack documentation or support channels.
## Parameters
### Common parameters
| Name | Description | Type | Value |
| ------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------- | ---------- | ------------------------ |
| `cluster` | Cluster configuration. | `object` | `{}` |
| `cluster.processCounts` | Process counts for different roles. | `object` | `{}` |
| `cluster.processCounts.stateless` | Number of stateless processes (-1 for automatic). | `int` | `-1` |
| `cluster.processCounts.storage` | Number of storage processes (determines cluster size). | `int` | `3` |
| `cluster.processCounts.cluster_controller` | Number of cluster controller processes. | `int` | `1` |
| `cluster.version` | Version of FoundationDB to use. | `string` | `7.3.63` |
| `cluster.redundancyMode` | Database redundancy mode (single, double, triple, three_datacenter, three_datacenter_fallback). | `string` | `double` |
| `cluster.storageEngine` | Storage engine (ssd-2, ssd-redwood-v1, ssd-rocksdb-v1, memory). | `string` | `ssd-2` |
| `cluster.faultDomain` | Fault domain configuration. | `object` | `{}` |
| `cluster.faultDomain.key` | Fault domain key. | `string` | `kubernetes.io/hostname` |
| `cluster.faultDomain.valueFrom` | Fault domain value source. | `string` | `spec.nodeName` |
| `storage` | Storage configuration. | `object` | `{}` |
| `storage.size` | Size of persistent volumes for each instance. | `quantity` | `16Gi` |
| `storage.storageClass` | Storage class (if not set, uses cluster default). | `string` | `""` |
| `resources` | Explicit CPU and memory configuration for each FoundationDB instance. When omitted, the preset defined in `resourcesPreset` is applied. | `object` | `{}` |
| `resources.cpu` | CPU available to each instance. | `quantity` | `""` |
| `resources.memory` | Memory (RAM) available to each instance. | `quantity` | `""` |
| `resourcesPreset` | Default sizing preset used when `resources` is omitted. | `string` | `medium` |
| `backup` | Backup configuration. | `object` | `{}` |
| `backup.enabled` | Enable backups. | `bool` | `false` |
| `backup.s3` | S3 configuration for backups. | `object` | `{}` |
| `backup.s3.bucket` | S3 bucket name. | `string` | `""` |
| `backup.s3.endpoint` | S3 endpoint URL. | `string` | `""` |
| `backup.s3.region` | S3 region. | `string` | `us-east-1` |
| `backup.s3.credentials` | S3 credentials. | `object` | `{}` |
| `backup.s3.credentials.accessKeyId` | S3 access key ID. | `string` | `""` |
| `backup.s3.credentials.secretAccessKey` | S3 secret access key. | `string` | `""` |
| `backup.retentionPolicy` | Retention policy for backups. | `string` | `7d` |
| `monitoring` | Monitoring configuration. | `object` | `{}` |
| `monitoring.enabled` | Enable WorkloadMonitor integration. | `bool` | `true` |
### FoundationDB configuration
| Name | Description | Type | Value |
| ---------------------------- | ------------------------------------------ | ---------- | --------- |
| `customParameters` | Custom parameters to pass to FoundationDB. | `[]string` | `[]` |
| `imageType` | Container image deployment type. | `string` | `unified` |
| `securityContext` | Security context for containers. | `object` | `{}` |
| `securityContext.runAsUser` | User ID to run the container. | `int` | `4059` |
| `securityContext.runAsGroup` | Group ID to run the container. | `int` | `4059` |
| `automaticReplacements` | Enable automatic pod replacements. | `bool` | `true` |

View File

@@ -1 +0,0 @@
../../../library/cozy-lib

View File

@@ -1,106 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="144"
height="144"
viewBox="0 0 144 144"
fill="none"
version="1.1"
id="svg4"
sodipodi:docname="foundationdb.svg"
inkscape:version="1.4.2 (unknown)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview4"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="6.0902778"
inkscape:cx="72"
inkscape:cy="72.492588"
inkscape:window-width="1920"
inkscape:window-height="1128"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg4" />
<rect
width="144"
height="144"
rx="24"
fill="url(#paint0_linear_fdb)"
id="rect1"
style="fill:#ffffff" />
<!-- FoundationDB Icon (scaled and positioned) -->
<!-- FoundationDB Text -->
<defs
id="defs4">
<linearGradient
id="paint0_linear_fdb"
x1="140"
y1="130.5"
x2="4"
y2="9.49999"
gradientUnits="userSpaceOnUse">
<stop
stop-color="#047BFE"
id="stop3" />
<stop
offset="1"
stop-color="#3F9AFB"
id="stop4" />
</linearGradient>
</defs>
<g
id="g1134"
transform="matrix(3.132791,0,0,3.132791,-115.98385,6.9294227)">
<g
transform="matrix(0.08541251,0,0,0.08541251,8.7615159,9.5962543)"
id="g10">
<polygon
style="fill:#3f9afb"
class="st0"
points="457.2,150.5 457.2,98.6 561.4,124 561.6,164.8 666.6,150.9 666.3,98.7 845.8,143 846.4,189.9 667.4,165.8 560.6,177.3 457.1,165.4 354.2,177.6 354.1,165.7 "
id="polygon4" />
<path
style="fill:#0b70e0"
inkscape:connector-curvature="0"
class="st1"
d="m 666.6,183.2 179.6,18.6 v 46 H 353.8 l -0.5,-12.2 h 103.5 c 0,0 0,-34.2 0,-52.3 34.8,3.4 103.8,10.2 103.8,10.2 v 40.9 h 106 z"
id="path6" />
<path
style="fill:#9eccfd"
inkscape:connector-curvature="0"
class="st2"
d="m 561.4,109.1 -0.3,-12.6 c 0,0 68.1,-20.4 103.3,-30.8 0,-16.9 0,-33.2 0,-52.9 61.8,24.8 121.2,48.8 181.2,72.9 0,15 0,29.4 0,45.4 -61.5,-16.9 -121.7,-33.5 -180.2,-49.6 -35.6,9.5 -104,27.6 -104,27.6 z"
id="path8" />
</g>
<polygon
transform="matrix(0.08541251,0,0,0.08541251,8.7795597,9.6869671)"
style="fill:#3f9afb"
class="st0"
points="666.6,150.9 666.3,98.7 845.8,143 846.4,189.9 667.4,165.8 560.6,177.3 457.1,165.4 354.2,177.6 354.1,165.7 457.2,150.5 457.2,98.6 561.4,124 561.6,164.8 "
id="polygon856" />
<path
style="fill:#0b70e0;stroke-width:0.0854125"
inkscape:connector-curvature="0"
class="st1"
d="m 65.715539,25.334539 15.340087,1.588673 v 3.928975 h -42.05712 l -0.04271,-1.042033 h 8.840195 c 0,0 0,-2.921107 0,-4.467074 2.972356,0.290403 8.865819,0.871208 8.865819,0.871208 v 3.493371 h 9.053726 z"
id="path858" />
<path
style="fill:#9eccfd;stroke-width:0.0854125"
inkscape:connector-curvature="0"
class="st2"
d="m 56.730143,19.005472 -0.02562,-1.076198 c 0,0 5.816592,-1.742415 8.823112,-2.630705 0,-1.443471 0,-2.835695 0,-4.518322 5.278493,2.11823 10.351997,4.168131 15.476747,6.226572 0,1.281188 0,2.511128 0,3.877728 -5.252869,-1.443471 -10.394702,-2.861319 -15.391334,-4.23646 -3.040686,0.811419 -8.882901,2.357385 -8.882901,2.357385 z"
id="path860" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.6 KiB

View File

@@ -1,47 +0,0 @@
{{/*
Common resource definitions
*/}}
{{- define "foundationdb.resources" -}}
{{- include "cozy-lib.resources.defaultingSanitize" (list .Values.resources.preset .Values.resources $) }}
{{- end }}
{{/*
Common labels
*/}}
{{- define "foundationdb.labels" -}}
helm.sh/chart: {{ include "foundationdb.chart" . }}
{{ include "foundationdb.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
Selector labels
*/}}
{{- define "foundationdb.selectorLabels" -}}
app.kubernetes.io/name: foundationdb
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
Chart name and version
*/}}
{{- define "foundationdb.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Calculate minReplicas for WorkloadMonitor based on redundancyMode
*/}}
{{- define "foundationdb.minReplicas" -}}
{{- $replicas := .Values.cluster.processCounts.storage -}}
{{- if or (eq .Values.cluster.redundancyMode "triple") (eq .Values.cluster.redundancyMode "three_data_hall") (eq .Values.cluster.redundancyMode "three_datacenter") (eq .Values.cluster.redundancyMode "three_datacenter_fallback") (eq .Values.cluster.redundancyMode "three_data_hall_fallback") }}
{{- print (max 1 (sub $replicas 2)) -}}
{{- else if eq .Values.cluster.redundancyMode "double" }}
{{- print (max 1 (sub $replicas 1)) -}}
{{- else }}
{{- print $replicas -}}
{{- end -}}
{{- end -}}

View File

@@ -1,65 +0,0 @@
{{- if .Values.backup.enabled }}
---
apiVersion: v1
kind: Secret
metadata:
name: {{ .Release.Name }}-s3-creds
labels:
app.kubernetes.io/name: foundationdb
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
type: Opaque
data:
AWS_ACCESS_KEY_ID: {{ .Values.backup.s3.credentials.accessKeyId | b64enc }}
AWS_SECRET_ACCESS_KEY: {{ .Values.backup.s3.credentials.secretAccessKey | b64enc }}
---
apiVersion: apps.foundationdb.org/v1beta2
kind: FoundationDBBackup
metadata:
name: {{ .Release.Name }}-backup
labels:
app.kubernetes.io/name: foundationdb
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
spec:
clusterName: {{ .Release.Name }}
backupState: Running
backupDeploymentSpec:
podTemplateSpec:
spec:
containers:
- name: foundationdb
resources:
limits:
cpu: 100m
memory: 128Mi
requests:
cpu: 100m
memory: 128Mi
securityContext:
runAsUser: 0
customParameters:
- backup_agent_snapshot_mode=0
snapshotPeriodSeconds: 3600
blobStoreConfiguration:
accountName: {{ .Values.backup.s3.bucket }}
bucket: {{ .Values.backup.s3.bucket }}
{{- if .Values.backup.s3.endpoint }}
endpoint: {{ .Values.backup.s3.endpoint }}
{{- end }}
credentials:
AWS_ACCESS_KEY_ID:
secretKeyRef:
name: {{ .Release.Name }}-s3-creds
key: AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY:
secretKeyRef:
name: {{ .Release.Name }}-s3-creds
key: AWS_SECRET_ACCESS_KEY
{{- end }}

View File

@@ -1,97 +0,0 @@
{{- $clusterDomain := index .Values._cluster "cluster-domain" | default "cozy.local" }}
---
apiVersion: apps.foundationdb.org/v1beta2
kind: FoundationDBCluster
metadata:
name: {{ .Release.Name }}
labels:
app.kubernetes.io/name: foundationdb
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
spec:
version: {{ .Values.cluster.version | quote }}
databaseConfiguration:
redundancy_mode: {{ .Values.cluster.redundancyMode }}
storage_engine: {{ .Values.cluster.storageEngine }}
processCounts:
{{- toYaml .Values.cluster.processCounts | nindent 4 }}
automationOptions:
replacements:
enabled: {{ .Values.automaticReplacements }}
faultDomain:
key: {{ .Values.cluster.faultDomain.key }}
{{- if .Values.cluster.faultDomain.valueFrom }}
valueFrom: {{ .Values.cluster.faultDomain.valueFrom }}
{{- end }}
imageType: {{ .Values.imageType }}
labels:
filterOnOwnerReference: false
matchLabels:
foundationdb.org/fdb-cluster-name: {{ .Release.Name }}
processClassLabels:
- foundationdb.org/fdb-process-class
processGroupIDLabels:
- foundationdb.org/fdb-process-group-id
minimumUptimeSecondsForBounce: 60
processes:
general:
{{- if .Values.customParameters }}
customParameters:
{{- range .Values.customParameters }}
- {{ . }}
{{- end }}
{{- end }}
podTemplate:
metadata:
labels:
policy.cozystack.io/allow-to-apiserver: "true"
spec:
serviceAccountName: {{ .Release.Name }}-foundationdb
securityContext:
fsGroup: {{ .Values.securityContext.runAsGroup }}
containers:
- name: foundationdb
resources: {{- include "cozy-lib.resources.defaultingSanitize" (list .Values.resourcesPreset .Values.resources $) | nindent 16 }}
securityContext:
{{- toYaml .Values.securityContext | nindent 16 }}
- name: foundationdb-kubernetes-sidecar
resources:
limits:
cpu: 100m
memory: 128Mi
requests:
cpu: 100m
memory: 128Mi
securityContext:
{{- toYaml .Values.securityContext | nindent 16 }}
initContainers:
- name: foundationdb-kubernetes-init
resources:
limits:
cpu: 100m
memory: 128Mi
requests:
cpu: 100m
memory: 128Mi
securityContext:
{{- toYaml .Values.securityContext | nindent 16 }}
volumeClaimTemplate:
spec:
{{- if .Values.storage.storageClass }}
storageClassName: {{ .Values.storage.storageClass }}
{{- end }}
resources:
requests:
storage: {{ .Values.storage.size }}
routing:
dnsDomain: {{ $clusterDomain }}
defineDNSLocalityFields: true
sidecarContainer:
enableLivenessProbe: true
enableReadinessProbe: true

View File

@@ -1,22 +0,0 @@
{{- if .Values.monitoring.enabled }}
---
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-resourcemap
labels:
app.kubernetes.io/name: foundationdb
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
app.cozystack.io/type: dashboard-resourcemap
data:
resources: |
- apiVersion: apps.foundationdb.org/v1beta2
kind: FoundationDBCluster
name: {{ .Release.Name }}
{{- if .Values.backup.enabled }}
- apiVersion: apps.foundationdb.org/v1beta2
kind: FoundationDBBackup
name: {{ .Release.Name }}-backup
{{- end }}
{{- end }}

View File

@@ -1,22 +0,0 @@
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: {{ .Release.Name }}-foundationdb
labels:
app.kubernetes.io/name: foundationdb
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
rules:
- apiGroups:
- ""
resources:
- pods
verbs:
- get
- list
- watch
- create
- update
- patch
- delete

View File

@@ -1,17 +0,0 @@
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: {{ .Release.Name }}-foundationdb
labels:
app.kubernetes.io/name: foundationdb
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: {{ .Release.Name }}-foundationdb
subjects:
- kind: ServiceAccount
name: {{ .Release.Name }}-foundationdb
namespace: {{ .Release.Namespace }}

View File

@@ -1,9 +0,0 @@
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ .Release.Name }}-foundationdb
labels:
app.kubernetes.io/name: foundationdb
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}

View File

@@ -1,20 +0,0 @@
{{- if .Values.monitoring.enabled }}
---
apiVersion: cozystack.io/v1alpha1
kind: WorkloadMonitor
metadata:
name: {{ .Release.Name }}
labels:
app.kubernetes.io/name: foundationdb
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
spec:
replicas: {{ .Values.cluster.processCounts.storage }}
minReplicas: {{ include "foundationdb.minReplicas" . }}
kind: foundationdb
type: foundationdb
selector:
foundationdb.org/fdb-cluster-name: {{ .Release.Name }}
foundationdb.org/fdb-process-class: storage
version: {{ .Chart.Version }}
{{- end }}

View File

@@ -1,287 +0,0 @@
{
"title": "Chart Values",
"type": "object",
"properties": {
"automaticReplacements": {
"description": "Enable automatic pod replacements.",
"type": "boolean",
"default": true
},
"backup": {
"description": "Backup configuration.",
"type": "object",
"default": {},
"required": [
"enabled",
"retentionPolicy",
"s3"
],
"properties": {
"enabled": {
"description": "Enable backups.",
"type": "boolean",
"default": false
},
"retentionPolicy": {
"description": "Retention policy for backups.",
"type": "string",
"default": "7d"
},
"s3": {
"description": "S3 configuration for backups.",
"type": "object",
"default": {},
"required": [
"bucket",
"credentials",
"endpoint",
"region"
],
"properties": {
"bucket": {
"description": "S3 bucket name.",
"type": "string",
"default": ""
},
"credentials": {
"description": "S3 credentials.",
"type": "object",
"default": {},
"required": [
"accessKeyId",
"secretAccessKey"
],
"properties": {
"accessKeyId": {
"description": "S3 access key ID.",
"type": "string",
"default": ""
},
"secretAccessKey": {
"description": "S3 secret access key.",
"type": "string",
"default": ""
}
}
},
"endpoint": {
"description": "S3 endpoint URL.",
"type": "string",
"default": ""
},
"region": {
"description": "S3 region.",
"type": "string",
"default": "us-east-1"
}
}
}
}
},
"cluster": {
"description": "Cluster configuration.",
"type": "object",
"default": {},
"required": [
"faultDomain",
"processCounts",
"redundancyMode",
"storageEngine",
"version"
],
"properties": {
"faultDomain": {
"description": "Fault domain configuration.",
"type": "object",
"default": {},
"required": [
"key",
"valueFrom"
],
"properties": {
"key": {
"description": "Fault domain key.",
"type": "string",
"default": "kubernetes.io/hostname"
},
"valueFrom": {
"description": "Fault domain value source.",
"type": "string",
"default": "spec.nodeName"
}
}
},
"processCounts": {
"description": "Process counts for different roles.",
"type": "object",
"default": {},
"required": [
"cluster_controller",
"stateless",
"storage"
],
"properties": {
"cluster_controller": {
"description": "Number of cluster controller processes.",
"type": "integer",
"default": 1
},
"stateless": {
"description": "Number of stateless processes (-1 for automatic).",
"type": "integer",
"default": -1
},
"storage": {
"description": "Number of storage processes (determines cluster size).",
"type": "integer",
"default": 3
}
}
},
"redundancyMode": {
"description": "Database redundancy mode (single, double, triple, three_datacenter, three_datacenter_fallback).",
"type": "string",
"default": "double"
},
"storageEngine": {
"description": "Storage engine (ssd-2, ssd-redwood-v1, ssd-rocksdb-v1, memory).",
"type": "string",
"default": "ssd-2"
},
"version": {
"description": "Version of FoundationDB to use.",
"type": "string",
"default": "7.3.63"
}
}
},
"customParameters": {
"description": "Custom parameters to pass to FoundationDB.",
"type": "array",
"default": [],
"items": {
"type": "string"
}
},
"imageType": {
"description": "Container image deployment type.",
"type": "string",
"default": "unified",
"enum": [
"unified",
"split"
]
},
"monitoring": {
"description": "Monitoring configuration.",
"type": "object",
"default": {},
"required": [
"enabled"
],
"properties": {
"enabled": {
"description": "Enable WorkloadMonitor integration.",
"type": "boolean",
"default": true
}
}
},
"resources": {
"description": "Explicit CPU and memory configuration for each FoundationDB instance. When omitted, the preset defined in `resourcesPreset` is applied.",
"type": "object",
"default": {},
"properties": {
"cpu": {
"description": "CPU available to each instance.",
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
"anyOf": [
{
"type": "integer"
},
{
"type": "string"
}
],
"x-kubernetes-int-or-string": true
},
"memory": {
"description": "Memory (RAM) available to each instance.",
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
"anyOf": [
{
"type": "integer"
},
{
"type": "string"
}
],
"x-kubernetes-int-or-string": true
}
}
},
"resourcesPreset": {
"description": "Default sizing preset used when `resources` is omitted.",
"type": "string",
"default": "medium",
"enum": [
"small",
"medium",
"large",
"xlarge",
"2xlarge"
]
},
"securityContext": {
"description": "Security context for containers.",
"type": "object",
"default": {},
"required": [
"runAsGroup",
"runAsUser"
],
"properties": {
"runAsGroup": {
"description": "Group ID to run the container.",
"type": "integer",
"default": 4059
},
"runAsUser": {
"description": "User ID to run the container.",
"type": "integer",
"default": 4059
}
}
},
"storage": {
"description": "Storage configuration.",
"type": "object",
"default": {},
"required": [
"size",
"storageClass"
],
"properties": {
"size": {
"description": "Size of persistent volumes for each instance.",
"default": "16Gi",
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
"anyOf": [
{
"type": "integer"
},
{
"type": "string"
}
],
"x-kubernetes-int-or-string": true
},
"storageClass": {
"description": "Storage class (if not set, uses cluster default).",
"type": "string",
"default": ""
}
}
}
}
}

View File

@@ -1,120 +0,0 @@
##
## @section Common parameters
##
## @typedef {struct} ClusterProcessCounts - Process counts for different roles.
## @field {int} stateless - Number of stateless processes (-1 for automatic).
## @field {int} storage - Number of storage processes (determines cluster size).
## @field {int} cluster_controller - Number of cluster controller processes.
## @typedef {struct} ClusterFaultDomain - Fault domain configuration.
## @field {string} key - Fault domain key.
## @field {string} valueFrom - Fault domain value source.
## @typedef {struct} Cluster - Cluster configuration.
## @field {ClusterProcessCounts} processCounts - Process counts for different roles.
## @field {string} version - Version of FoundationDB to use.
## @field {string} redundancyMode - Database redundancy mode (single, double, triple, three_datacenter, three_datacenter_fallback).
## @field {string} storageEngine - Storage engine (ssd-2, ssd-redwood-v1, ssd-rocksdb-v1, memory).
## @field {ClusterFaultDomain} faultDomain - Fault domain configuration.
## @param {Cluster} cluster - Cluster configuration.
cluster:
processCounts:
stateless: -1
storage: 3
cluster_controller: 1
version: "7.3.63"
redundancyMode: "double"
storageEngine: "ssd-2"
faultDomain:
key: "kubernetes.io/hostname"
valueFrom: "spec.nodeName"
## @typedef {struct} Storage - Storage configuration.
## @field {quantity} size - Size of persistent volumes for each instance.
## @field {string} storageClass - Storage class (if not set, uses cluster default).
## @param {Storage} storage - Storage configuration.
storage:
size: "16Gi"
storageClass: ""
## @typedef {struct} Resources - Explicit CPU and memory configuration for each FoundationDB instance.
## @field {quantity} [cpu] - CPU available to each instance.
## @field {quantity} [memory] - Memory (RAM) available to each instance.
## @enum {string} ResourcesPreset - Default sizing preset.
## @value small
## @value medium
## @value large
## @value xlarge
## @value 2xlarge
## @param {Resources} [resources] - Explicit CPU and memory configuration for each FoundationDB instance. When omitted, the preset defined in `resourcesPreset` is applied.
resources: {}
## @param {ResourcesPreset} resourcesPreset="medium" - Default sizing preset used when `resources` is omitted.
resourcesPreset: "medium"
## @typedef {struct} BackupS3Credentials - S3 credentials.
## @field {string} accessKeyId - S3 access key ID.
## @field {string} secretAccessKey - S3 secret access key.
## @typedef {struct} BackupS3 - S3 configuration for backups.
## @field {string} bucket - S3 bucket name.
## @field {string} endpoint - S3 endpoint URL.
## @field {string} region - S3 region.
## @field {BackupS3Credentials} credentials - S3 credentials.
## @typedef {struct} Backup - Backup configuration.
## @field {bool} enabled - Enable backups.
## @field {BackupS3} s3 - S3 configuration for backups.
## @field {string} retentionPolicy - Retention policy for backups.
## @param {Backup} backup - Backup configuration.
backup:
enabled: false
s3:
bucket: ""
endpoint: ""
region: "us-east-1"
credentials:
accessKeyId: ""
secretAccessKey: ""
retentionPolicy: "7d"
## @typedef {struct} Monitoring - Monitoring configuration.
## @field {bool} enabled - Enable WorkloadMonitor integration.
## @param {Monitoring} monitoring - Monitoring configuration.
monitoring:
enabled: true
##
## @section FoundationDB configuration
##
## @param {[]string} customParameters - Custom parameters to pass to FoundationDB.
customParameters: []
## @enum {string} ImageType - Container image deployment type.
## @value unified
## @value split
## @param {ImageType} imageType="unified" - Container image deployment type.
imageType: "unified"
## @typedef {struct} SecurityContext - Security context for containers.
## @field {int} runAsUser - User ID to run the container.
## @field {int} runAsGroup - Group ID to run the container.
## @param {SecurityContext} securityContext - Security context for containers.
securityContext:
runAsUser: 4059
runAsGroup: 4059
## @param {bool} automaticReplacements - Enable automatic pod replacements.
automaticReplacements: true

View File

@@ -62,40 +62,40 @@ The deployment architecture is illustrated in the diagram below:
| Name | Description | Type | Value |
| -------------- | ------------------------------------------------------------ | ---------- | ------- |
| `size` | Persistent Volume Claim size available for application data. | `quantity` | `10Gi` |
| `storageClass` | StorageClass used to store the data. | `string` | `""` |
| `external` | Enable external access from outside the cluster. | `bool` | `false` |
| `size` | Persistent Volume Claim size, available for application data | `quantity` | `10Gi` |
| `storageClass` | StorageClass used to store the data | `string` | `""` |
| `external` | Enable external access from outside the cluster | `bool` | `false` |
### Application-specific parameters
| Name | Description | Type | Value |
| ----------- | ------------------------------------------------ | ---------- | ----- |
| `endpoints` | Endpoints configuration, as a list of <ip:port>. | `[]string` | `[]` |
| Name | Description | Type | Value |
| ----------- | ----------------------------------------------- | ---------- | ----- |
| `endpoints` | Endpoints configuration, as a list of <ip:port> | `[]string` | `[]` |
### HAProxy parameters
| Name | Description | Type | Value |
| -------------------------- | -------------------------------------------------------------------------------------------------------- | ---------- | ------ |
| `haproxy` | HAProxy configuration. | `object` | `{}` |
| `haproxy.replicas` | Number of HAProxy replicas. | `int` | `2` |
| `haproxy.resources` | Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied. | `object` | `{}` |
| `haproxy.resources.cpu` | CPU available to each replica. | `quantity` | `""` |
| `haproxy.resources.memory` | Memory (RAM) available to each replica. | `quantity` | `""` |
| `haproxy.resourcesPreset` | Default sizing preset used when `resources` is omitted. | `string` | `nano` |
| Name | Description | Type | Value |
| -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | ----------- | ------ |
| `haproxy` | HAProxy configuration | `object` | `{}` |
| `haproxy.replicas` | Number of HAProxy replicas | `int` | `2` |
| `haproxy.resources` | Explicit CPU and memory configuration for each replica. When left empty, the preset defined in `resourcesPreset` is applied. | `object` | `{}` |
| `haproxy.resources.cpu` | CPU available to each replica | `*quantity` | `null` |
| `haproxy.resources.memory` | Memory (RAM) available to each replica | `*quantity` | `null` |
| `haproxy.resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`. | `string` | `nano` |
### Nginx parameters
| Name | Description | Type | Value |
| ------------------------ | -------------------------------------------------------------------------------------------------------- | ---------- | ------ |
| `nginx` | Nginx configuration. | `object` | `{}` |
| `nginx.replicas` | Number of Nginx replicas. | `int` | `2` |
| `nginx.resources` | Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied. | `object` | `{}` |
| `nginx.resources.cpu` | CPU available to each replica. | `quantity` | `""` |
| `nginx.resources.memory` | Memory (RAM) available to each replica. | `quantity` | `""` |
| `nginx.resourcesPreset` | Default sizing preset used when `resources` is omitted. | `string` | `nano` |
| Name | Description | Type | Value |
| ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------- | ----------- | ------ |
| `nginx` | Nginx configuration | `object` | `{}` |
| `nginx.replicas` | Number of Nginx replicas | `int` | `2` |
| `nginx.resources` | Explicit CPU and memory configuration for each replica. When left empty, the preset defined in `resourcesPreset` is applied. | `*object` | `null` |
| `nginx.resources.cpu` | CPU available to each replica | `*quantity` | `null` |
| `nginx.resources.memory` | Memory (RAM) available to each replica | `*quantity` | `null` |
| `nginx.resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`. | `string` | `nano` |
## Parameter examples and reference

View File

@@ -1 +1 @@
ghcr.io/cozystack/cozystack/nginx-cache:0.0.0@sha256:cb25e40cb665b8bbeee8cb1ec39da4c9a7452ef3f2f371912bbc0d1b1e2d40a8
ghcr.io/cozystack/cozystack/nginx-cache:0.0.0@sha256:e0a07082bb6fc6aeaae2315f335386f1705a646c72f9e0af512aebbca5cb2b15

View File

@@ -3,7 +3,7 @@
"type": "object",
"properties": {
"endpoints": {
"description": "Endpoints configuration, as a list of \u003cip:port\u003e.",
"description": "Endpoints configuration, as a list of \u003cip:port\u003e",
"type": "array",
"default": [],
"items": {
@@ -11,31 +11,32 @@
}
},
"external": {
"description": "Enable external access from outside the cluster.",
"description": "Enable external access from outside the cluster",
"type": "boolean",
"default": false
},
"haproxy": {
"description": "HAProxy configuration.",
"description": "HAProxy configuration",
"type": "object",
"default": {},
"required": [
"replicas",
"resources",
"resourcesPreset"
],
"properties": {
"replicas": {
"description": "Number of HAProxy replicas.",
"description": "Number of HAProxy replicas",
"type": "integer",
"default": 2
},
"resources": {
"description": "Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied.",
"description": "Explicit CPU and memory configuration for each replica. When left empty, the preset defined in `resourcesPreset` is applied.",
"type": "object",
"default": {},
"properties": {
"cpu": {
"description": "CPU available to each replica.",
"description": "CPU available to each replica",
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
"anyOf": [
{
@@ -48,7 +49,7 @@
"x-kubernetes-int-or-string": true
},
"memory": {
"description": "Memory (RAM) available to each replica.",
"description": "Memory (RAM) available to each replica",
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
"anyOf": [
{
@@ -63,7 +64,7 @@
}
},
"resourcesPreset": {
"description": "Default sizing preset used when `resources` is omitted.",
"description": "Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`.",
"type": "string",
"default": "nano",
"enum": [
@@ -79,7 +80,7 @@
}
},
"nginx": {
"description": "Nginx configuration.",
"description": "Nginx configuration",
"type": "object",
"default": {},
"required": [
@@ -88,17 +89,17 @@
],
"properties": {
"replicas": {
"description": "Number of Nginx replicas.",
"description": "Number of Nginx replicas",
"type": "integer",
"default": 2
},
"resources": {
"description": "Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied.",
"description": "Explicit CPU and memory configuration for each replica. When left empty, the preset defined in `resourcesPreset` is applied.",
"type": "object",
"default": {},
"properties": {
"cpu": {
"description": "CPU available to each replica.",
"description": "CPU available to each replica",
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
"anyOf": [
{
@@ -111,7 +112,7 @@
"x-kubernetes-int-or-string": true
},
"memory": {
"description": "Memory (RAM) available to each replica.",
"description": "Memory (RAM) available to each replica",
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
"anyOf": [
{
@@ -126,7 +127,7 @@
}
},
"resourcesPreset": {
"description": "Default sizing preset used when `resources` is omitted.",
"description": "Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`.",
"type": "string",
"default": "nano",
"enum": [
@@ -142,7 +143,7 @@
}
},
"size": {
"description": "Persistent Volume Claim size available for application data.",
"description": "Persistent Volume Claim size, available for application data",
"default": "10Gi",
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
"anyOf": [
@@ -156,9 +157,8 @@
"x-kubernetes-int-or-string": true
},
"storageClass": {
"description": "StorageClass used to store the data.",
"type": "string",
"default": ""
"description": "StorageClass used to store the data",
"type": "string"
}
}
}

View File

@@ -1,22 +1,14 @@
##
## @section Common parameters
##
## @param {quantity} size - Persistent Volume Claim size available for application data.
## @param size {quantity} Persistent Volume Claim size, available for application data
size: 10Gi
## @param {string} storageClass - StorageClass used to store the data.
## @param storageClass {string} StorageClass used to store the data
storageClass: ""
## @param {bool} external - Enable external access from outside the cluster.
## @param external {bool} Enable external access from outside the cluster
external: false
##
## @section Application-specific parameters
##
## @param {[]string} endpoints - Endpoints configuration, as a list of <ip:port>.
endpoints: []
## @param endpoints {[]string} Endpoints configuration, as a list of <ip:port>
## Example:
## endpoints:
## - 10.100.3.1:80
@@ -25,46 +17,37 @@ endpoints: []
## - 10.100.3.12:80
## - 10.100.3.3:80
## - 10.100.3.13:80
##
endpoints: []
## @section HAProxy parameters
##
## @typedef {struct} Resources - Explicit CPU and memory configuration for each replica.
## @field {quantity} [cpu] - CPU available to each replica.
## @field {quantity} [memory] - Memory (RAM) available to each replica.
## @enum {string} ResourcesPreset - Default sizing preset.
## @value nano
## @value micro
## @value small
## @value medium
## @value large
## @value xlarge
## @value 2xlarge
## @typedef {struct} HAProxy - HAProxy configuration.
## @field {int} replicas - Number of HAProxy replicas.
## @field {Resources} [resources] - Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied.
## @field {ResourcesPreset} resourcesPreset - Default sizing preset used when `resources` is omitted.
## @param {HAProxy} haproxy - HAProxy configuration.
## @param haproxy {haproxy} HAProxy configuration
haproxy:
## @field haproxy.replicas {int} Number of HAProxy replicas
replicas: 2
## @field haproxy.resources {resources} Explicit CPU and memory configuration for each replica. When left empty, the preset defined in `resourcesPreset` is applied.
## @field resources.cpu {*quantity} CPU available to each replica
## @field resources.memory {*quantity} Memory (RAM) available to each replica
resources: {}
# resources:
# cpu: 4000m
# memory: 4Gi
## @field haproxy.resourcesPreset {string enum:"nano,micro,small,medium,large,xlarge,2xlarge"} Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`.
resourcesPreset: "nano"
##
## @section Nginx parameters
##
## @typedef {struct} Nginx - Nginx configuration.
## @field {int} replicas - Number of Nginx replicas.
## @field {Resources} [resources] - Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied.
## @field {ResourcesPreset} resourcesPreset - Default sizing preset used when `resources` is omitted.
## @param {Nginx} nginx - Nginx configuration.
## @param nginx {nginx} Nginx configuration
nginx:
## @field nginx.replicas {int} Number of Nginx replicas
replicas: 2
## @field nginx.resources {*resources} Explicit CPU and memory configuration for each replica. When left empty, the preset defined in `resourcesPreset` is applied.
# resources:
# cpu: 4000m
# memory: 4Gi
resources: {}
## @field nginx.resourcesPreset {string enum:"nano,micro,small,medium,large,xlarge,2xlarge"} Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`.
resourcesPreset: "nano"

Some files were not shown because too many files have changed in this diff Show More