Compare commits

...

47 Commits

Author SHA1 Message Date
Andrei Kvapil
8b97d87d90 Refactor and implement TenantSecret
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
2025-08-05 16:34:36 +02:00
Andrei Kvapil
991e0479b9 filter namespaces by checking access to them
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
2025-08-05 16:34:27 +02:00
Andrei Kvapil
7c5152963d [cozystack-api] Implement TenantNamespace resource
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
2025-08-05 16:34:20 +02:00
Andrei Kvapil
cd80a73446 [dashboard] fix diff editor
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
2025-08-05 12:54:47 +02:00
Timofei Larkin
c74df866e6 [kubernetes] Disable VPA for VPA in tenant k8s (#1301)
## What this PR does

This patch disables the VPA for VPA deployment in tenant kubernetes
clusters. This feature was never designed for deployment in tenant
clusters and causes unexpected errors.

### Release note

```release-note
[kubernetes] Disable VPA for VPA feature for tenant clusters, fixing an unintended regression.
```

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

* **New Features**
* Added a new configuration option to enable or disable vertical pod
autoscaling for the autoscaler itself.

* **Chores**
  * Updated the Kubernetes application chart version to 0.26.3.
  * Updated version mapping for the Kubernetes package.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-04 18:46:37 +04:00
Timofei Larkin
080289fa00 [kubernetes] Disable VPA for VPA in tenant k8s
This patch disables the VPA for VPA deployment in tenant kubernetes
clusters. This feature was never designed for deployment in tenant
clusters and causes unexpected errors.

[kubernetes] Disable VPA for VPA feature for tenant clusters, fixing an
unintended regression.

Signed-off-by: Timofei Larkin <lllamnyp@gmail.com>
2025-08-04 16:47:48 +03:00
Timofei Larkin
98f86269f3 [virtual-machine] Disable instanceType validation (#1300)
## What this PR does

Workaround for #1299. If a Cozystack installation provides custom
instance types for virtual machines, the static validation rules prevent
such instance types from being used, as they are included in the OpenAPI
schema of the Cozystack API server and then once more applied in the
dependent HelmRelease, offering users no easy way to remedy this in
runtime.

### Release note

```release-note
[virtual-machine] Disable instanceType validation to enable using custom instance types.
```





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

* **New Features**
* Updated chart versions for virtual machine and VM instance
applications.
* **Refactor**
* Relaxed restrictions on instance type selection, allowing any string
value.
* **Chores**
* Updated version mappings for virtual machine and VM instance packages.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-04 16:45:33 +04:00
Timofei Larkin
44fabd4abc [virtual-machine] Disable instanceType validation
Workaround for #1299. If a Cozystack installation provides custom
instance types for virtual machines, the static validation rules prevent
such instance types from being used, as they are included in the OpenAPI
schema of the Cozystack API server and then once more applied in the
dependent HelmRelease, offering users no easy way to remedy this in
runtime.

[virtual-machine] Disable instanceType validation to enable using custom
instance types.

Signed-off-by: Timofei Larkin <lllamnyp@gmail.com>
2025-08-04 15:16:32 +03:00
Andrei Kvapil
8ddbe32ea1 Release v0.35.0-alpha.3 (#1295)
This PR prepares the release `v0.35.0-alpha.3`.

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

## Summary by CodeRabbit

* **Chores**
* Updated multiple container image tags and digests across various
components to newer versions, including core, monitoring, storage, and
dashboard services.
* Refreshed version references in configuration files to align with the
latest releases.
  * No changes to user-facing features or configuration options.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-01 19:01:19 +02:00
Andrei Kvapil
432ddf6abc [ci] Fix creating draft release
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
2025-08-01 18:59:15 +02:00
cozystack-bot
9d184a098f Prepare release v0.35.0-alpha.3
Signed-off-by: cozystack-bot <217169706+cozystack-bot@users.noreply.github.com>
2025-08-01 13:07:01 +00:00
Andrei Kvapil
24807cb679 [cozystack-api] fix type for ApplicationList (#1290)
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

```
# kubectl get --raw /apis/apps.cozystack.io/v1alpha1/namespaces/tenant-whmcs/vminstances  | jq .
```

was showing:

```
{
  "apiVersion": "apps.cozystack.io/v1alpha1",
  "items": [],
  "kind": "BucketList",
  "metadata": {
    "resourceVersion": "123218712"
  }
}
```

now it shows:

```
{
  "apiVersion": "apps.cozystack.io/v1alpha1",
  "items": [],
  "kind": "VMInstanceList",
  "metadata": {
    "resourceVersion": "123218712"
  }
}
```

### 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] fix type for ApplicationList
```

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

* **Refactor**
* Improved how application lists are constructed and returned, using a
more flexible unstructured format for responses.
* Enhanced data handling to support new list formats for better
compatibility.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-01 14:34:48 +02:00
Andrei Kvapil
cd8e8bee0a [dx] Allow to not specify BUILDER for makefile if PLATFORM specified (#1288)
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
[dx] Allow to not specify BUILDER for makefile if PLATFORM specified
```

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

## Summary by CodeRabbit

* **Refactor**
* Improved handling of the PLATFORM variable to ensure it is only set
when undefined, providing clearer and more predictable behavior.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-01 12:53:41 +02:00
Andrei Kvapil
856720004f [seaweed] add tests for S3 buckets (#1283)
<!-- 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
Introduced automated end-to-end testing for SeaweedFS bucket creation
and verification in Kubernetes environments.

### 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
[seaweed] add tests for S3 buckets
```

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

## Summary by CodeRabbit

* **New Features**
* Introduced an end-to-end test for SeaweedFS Bucket resources,
including creation, credential verification, file upload, and cleanup.
* **Chores**
* Updated test scripts to include SeaweedFS in tenant configuration and
extended wait times for application readiness.
* Enhanced test environment by adding the MinIO client to the Docker
image for improved S3 compatibility testing.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-01 12:52:33 +02:00
Andrei Kvapil
d1ad5ff222 [monitoring] add seaweedfs monitoring (#1285)
<!-- 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
add seaweedfs monitoring and grafana dashboard

### 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
- add seaweedfs monitoring and grafana dashboard
```

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

## Summary by CodeRabbit

* **New Features**
* Added a new SeaweedFS monitoring dashboard to the available monitoring
options.
* Enabled global monitoring configuration and enhanced SeaweedFS S3
service settings, including authentication and readiness probe.

* **Bug Fixes**
* Corrected how annotations are applied to the SeaweedFS volume service
monitor to ensure proper configuration inheritance.

* **Chores**
  * Updated monitoring package version to 1.12.1.
  * Adjusted version mapping for the monitoring package.
* Applied patch to fix volume service monitor configuration in SeaweedFS
setup.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-01 12:50:55 +02:00
Andrei Kvapil
c81c9d255a dashboard auth-proxy enable cookie-secure (#1287)
<!-- 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 auth-proxy enable cookie-secure

### 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 auth-proxy enable cookie-secure
```

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

* **Chores**
  * Updated Keycloak client redirect URI to use HTTPS instead of HTTP.
* Improved authentication security by adjusting cookie and SSL settings.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-01 12:50:24 +02:00
Andrei Kvapil
f057d92a4d [cozystack-api] fix type for ApplicationList
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
2025-07-31 22:58:55 +02:00
klinch0
1ab63187c9 Update packages/system/keycloak-configure/templates/configure-kk.yaml
Co-authored-by: Timofei Larkin <lllamnyp@gmail.com>
Signed-off-by: klinch0 <68821526+klinch0@users.noreply.github.com>
2025-07-31 17:13:25 +03:00
klinch0
2fa56fc1e1 k8s make volumesnapshot crd name shorter (#1284)
<!-- 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
- k8s make volumesnapshot crd name shorter
```

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

* **Chores**
  * Updated chart version for the Kubernetes application.
* Changed Helm chart and namespace references to use a new, shorter
name.
* Updated version mapping to reflect the latest Kubernetes package
version.
* Renamed the Helm chart for volume snapshot resources to a shorter
name.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-31 17:12:57 +03:00
IvanHunters
36ccfb9509 add limits for s3 deployment
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2025-07-31 11:30:35 +03:00
klinch0
cb3cb99d06 [keycloak] keep admin password in secret (#1286)
<!-- 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
keep admin password in secret

### 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
- keep admin password in secret
```
2025-07-31 10:35:45 +03:00
Andrei Kvapil
8704767ac5 [dx] Allow to not specify BUILDER for makefile if PLATFORM specified
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
2025-07-30 16:46:07 +02:00
IvanHunters
03c4bf904f add handle of patch in makefile
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2025-07-30 17:38:50 +03:00
IvanHunters
dca2eb7ae8 fix chart version
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2025-07-30 17:08:54 +03:00
IvanHunters
1d9465d662 revert of metrics port for s3
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2025-07-30 16:59:11 +03:00
IvanHunters
53241efe63 fix values file
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2025-07-30 16:46:27 +03:00
IvanHunters
940b0b18b0 fix values for seadeed monitoring
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2025-07-30 16:39:14 +03:00
IvanHunters
824c72318a fix patches
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2025-07-30 16:31:24 +03:00
IvanHunters
0d7e856186 delete patch for seaweedfs
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2025-07-30 16:29:44 +03:00
IvanHunters
2897813dda revert bump version of seaweed in extra
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2025-07-30 16:26:01 +03:00
IvanHunters
e3a61b23af fix versions map
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2025-07-30 16:20:09 +03:00
kklinch0
7918e282bf keycloak enable cookie-secure
Signed-off-by: kklinch0 <kklinch0@gmail.com>
2025-07-30 16:07:30 +03:00
IvanHunters
0e428810fd [fix] add patches
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2025-07-30 16:02:12 +03:00
IvanHunters
fa4fff2292 [monitoring] add seaweedfs monitoring
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2025-07-30 15:17:46 +03:00
IvanHunters
0e875b17d1 [keycloak] keep admin password in secret
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2025-07-30 14:06:57 +03:00
kklinch0
efb2c632e2 k8s make volumesnapshot crd name shorter
Signed-off-by: kklinch0 <kklinch0@gmail.com>
2025-07-30 13:28:23 +03:00
Timofei Larkin
8951bc13d7 [cozystack-api] Configure dynamic api via custom resources (#1230)
## What this PR does

This patch introduces a new CRD to manage the configuration of the
Cozystack extension API server. Configuration previously done with a
single ConfigMap containing a list of objects is now decomposed into a
number of custom resources. Platform administrators receive a better UX
for defining their own custom Cozystack managed applications in addition
to the existing apps shipped with the default Cozystack installation.

### Release note

```release-note
[cozystack-api] Provide an API for administrators to define custom managed applications alongside existing managed apps.
```

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

## Summary by CodeRabbit

* **New Features**
* Introduced a new Kubernetes CustomResourceDefinition (CRD) for
managing resource definitions dynamically via the cluster.
* Added multiple resource definitions for various application types
using the new CRD.

* **Improvements**
* The API server now loads resource definitions dynamically from the
cluster instead of a static configuration file.
* Updated RBAC permissions to allow access to the new resource
definitions.

* **Removals**
* Removed the static ConfigMap-based resource configuration and related
file loading logic from the deployment and codebase.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Signed-off-by: Timofei Larkin <lllamnyp@gmail.com>
2025-07-29 18:31:53 +04:00
kklinch0
830ec252b9 Scaffold CozyRD CRD
Signed-off-by: Timofei Larkin <lllamnyp@gmail.com>
2025-07-29 17:03:22 +03:00
IvanHunters
730584bd15 [seaweed] add tests
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2025-07-28 16:18:07 +03:00
Andrei Kvapil
0e47e1e8ac Release v0.35.0-alpha.2 (#1278)
This PR prepares the release `v0.35.0-alpha.2`.

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

* **Chores**
* Updated container image tags and digests across multiple components to
new versions, primarily moving from `v0.35.0-alpha.1` to
`v0.35.0-alpha.2`.
* Refreshed image digests for several services, ensuring the latest
builds are used.
  * Updated dashboard version display to reflect the new release.
* Incremented version tags for Kubernetes-related images and other
system components with corresponding digest updates.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-25 21:40:16 +02:00
cozystack-bot
9617071ada Prepare release v0.35.0-alpha.2
Signed-off-by: cozystack-bot <217169706+cozystack-bot@users.noreply.github.com>
2025-07-25 16:43:50 +00:00
Andrei Kvapil
3b32bfe149 Fix building Kubevirt CCM
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
2025-07-25 17:49:11 +02:00
Andrei Kvapil
d9a5e9d628 Fix regression with optiona=true field
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
2025-07-25 17:44:38 +02:00
Andrei Kvapil
0feeaadb9c [kubernetes] Add dependency for snapshot CRD and migration to latest version (#1275)
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
[kubernetes] Add dependency for snapshot CRD and migration to latest version
```

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

## Summary by CodeRabbit

* **New Features**
* Added a migration script to automatically update Kubernetes custom
resources to app version 0.26.1 and track migration status.
* **Bug Fixes**
* Improved HelmRelease dependency management by adding a required
dependency for volume snapshot CRDs.
* **Chores**
  * Updated Kubernetes app version to 0.26.1.
  * Refreshed version mapping to reflect the latest release.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-25 17:11:06 +02:00
Andrei Kvapil
8fac3bfcb1 [seaweedfs] Client mode refactoring and fix issues (#1277)
- update cosi-driver
- add support exporting via nginx-ingress
- add support for whitelist

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
[seaweedfs] Client mode refactoring and fix issues

- update cosi-driver
- add support exporting via nginx-ingress
- add support for whitelist
```
2025-07-25 04:06:47 +02:00
Andrei Kvapil
b1e4ebeafc [seaweedfs] Client mode refactoring and fix issues
- update cosi-driver
- add support exporting via nginx-ingress
- add support for whitelist

Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
2025-07-25 04:06:11 +02:00
Andrei Kvapil
02436f312f [kubernetes] Add dependency for snapshot CRD and migration to latest version
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
2025-07-24 20:27:26 +02:00
100 changed files with 6315 additions and 776 deletions

View File

@@ -149,36 +149,35 @@ jobs:
version: ${{ steps.tag.outputs.tag }} # A
compare-to: ${{ steps.latest_release.outputs.tag }} # B
# Create or reuse DRAFT GitHub Release
# Create or reuse draft release
- name: Create / reuse draft release
if: steps.check_release.outputs.skip == 'false'
id: release
uses: actions/github-script@v7
with:
script: |
const tag = '${{ steps.tag.outputs.tag }}';
const isRc = ${{ steps.tag.outputs.is_rc }};
const outdated = '${{ steps.semver.outputs.comparison-result }}' === '<';
const makeLatest = outdated ? false : 'legacy';
const releases = await github.rest.repos.listReleases({
const tag = '${{ steps.tag.outputs.tag }}';
const isRc = ${{ steps.tag.outputs.is_rc }};
const releases = await github.rest.repos.listReleases({
owner: context.repo.owner,
repo: context.repo.repo
});
let rel = releases.data.find(r => r.tag_name === tag);
let rel = releases.data.find(r => r.tag_name === tag);
if (!rel) {
rel = await github.rest.repos.createRelease({
owner: context.repo.owner,
repo: context.repo.repo,
tag_name: tag,
name: tag,
draft: true,
prerelease: isRc,
make_latest: makeLatest
tag_name: tag,
name: tag,
draft: true,
prerelease: isRc // no make_latest for drafts
});
console.log(`Draft release created for ${tag}`);
} else {
console.log(`Re-using existing release ${tag}`);
}
core.setOutput('upload_url', rel.upload_url);
# Build + upload assets (optional)

2
.gitignore vendored
View File

@@ -77,3 +77,5 @@ fabric.properties
.DS_Store
**/.DS_Store
tmp/

View File

@@ -0,0 +1,89 @@
/*
Copyright 2025.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1alpha1
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// +kubebuilder:object:root=true
// CozystackResourceDefinition is the Schema for the cozystackresourcedefinitions API
type CozystackResourceDefinition struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec CozystackResourceDefinitionSpec `json:"spec,omitempty"`
}
// +kubebuilder:object:root=true
// CozystackResourceDefinitionList contains a list of CozystackResourceDefinition
type CozystackResourceDefinitionList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []CozystackResourceDefinition `json:"items"`
}
func init() {
SchemeBuilder.Register(&CozystackResourceDefinition{}, &CozystackResourceDefinitionList{})
}
type CozystackResourceDefinitionSpec struct {
// Application configuration
Application CozystackResourceDefinitionApplication `json:"application"`
// Release configuration
Release CozystackResourceDefinitionRelease `json:"release"`
}
type CozystackResourceDefinitionChart struct {
// Name of the Helm chart
Name string `json:"name"`
// Source reference for the Helm chart
SourceRef SourceRef `json:"sourceRef"`
}
type SourceRef struct {
// Kind of the source reference
// +kubebuilder:default:="HelmRepository"
Kind string `json:"kind"`
// Name of the source reference
Name string `json:"name"`
// Namespace of the source reference
// +kubebuilder:default:="cozy-public"
Namespace string `json:"namespace"`
}
type CozystackResourceDefinitionApplication struct {
// Kind of the application, used for UI and API
Kind string `json:"kind"`
// OpenAPI schema for the application, used for API validation
OpenAPISchema string `json:"openAPISchema"`
// Plural name of the application, used for UI and API
Plural string `json:"plural"`
// Singular name of the application, used for UI and API
Singular string `json:"singular"`
}
type CozystackResourceDefinitionRelease struct {
// Helm chart configuration
Chart CozystackResourceDefinitionChart `json:"chart"`
// Labels for the release
Labels map[string]string `json:"labels,omitempty"`
// Prefix for the release name
Prefix string `json:"prefix"`
}

View File

@@ -25,6 +25,135 @@ import (
runtime "k8s.io/apimachinery/pkg/runtime"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CozystackResourceDefinition) DeepCopyInto(out *CozystackResourceDefinition) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
in.Spec.DeepCopyInto(&out.Spec)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CozystackResourceDefinition.
func (in *CozystackResourceDefinition) DeepCopy() *CozystackResourceDefinition {
if in == nil {
return nil
}
out := new(CozystackResourceDefinition)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *CozystackResourceDefinition) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CozystackResourceDefinitionApplication) DeepCopyInto(out *CozystackResourceDefinitionApplication) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CozystackResourceDefinitionApplication.
func (in *CozystackResourceDefinitionApplication) DeepCopy() *CozystackResourceDefinitionApplication {
if in == nil {
return nil
}
out := new(CozystackResourceDefinitionApplication)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CozystackResourceDefinitionChart) DeepCopyInto(out *CozystackResourceDefinitionChart) {
*out = *in
out.SourceRef = in.SourceRef
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CozystackResourceDefinitionChart.
func (in *CozystackResourceDefinitionChart) DeepCopy() *CozystackResourceDefinitionChart {
if in == nil {
return nil
}
out := new(CozystackResourceDefinitionChart)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CozystackResourceDefinitionList) DeepCopyInto(out *CozystackResourceDefinitionList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]CozystackResourceDefinition, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CozystackResourceDefinitionList.
func (in *CozystackResourceDefinitionList) DeepCopy() *CozystackResourceDefinitionList {
if in == nil {
return nil
}
out := new(CozystackResourceDefinitionList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *CozystackResourceDefinitionList) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CozystackResourceDefinitionRelease) DeepCopyInto(out *CozystackResourceDefinitionRelease) {
*out = *in
out.Chart = in.Chart
if in.Labels != nil {
in, out := &in.Labels, &out.Labels
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CozystackResourceDefinitionRelease.
func (in *CozystackResourceDefinitionRelease) DeepCopy() *CozystackResourceDefinitionRelease {
if in == nil {
return nil
}
out := new(CozystackResourceDefinitionRelease)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CozystackResourceDefinitionSpec) DeepCopyInto(out *CozystackResourceDefinitionSpec) {
*out = *in
out.Application = in.Application
in.Release.DeepCopyInto(&out.Release)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CozystackResourceDefinitionSpec.
func (in *CozystackResourceDefinitionSpec) DeepCopy() *CozystackResourceDefinitionSpec {
if in == nil {
return nil
}
out := new(CozystackResourceDefinitionSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in Selector) DeepCopyInto(out *Selector) {
{
@@ -46,6 +175,21 @@ func (in Selector) DeepCopy() Selector {
return *out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *SourceRef) DeepCopyInto(out *SourceRef) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SourceRef.
func (in *SourceRef) DeepCopy() *SourceRef {
if in == nil {
return nil
}
out := new(SourceRef)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Workload) DeepCopyInto(out *Workload) {
*out = *in

View File

@@ -26,8 +26,8 @@ import (
func main() {
ctx := genericapiserver.SetupSignalContext()
options := server.NewAppsServerOptions(os.Stdout, os.Stderr)
cmd := server.NewCommandStartAppsServer(ctx, options)
options := server.NewCozyServerOptions(os.Stdout, os.Stderr)
cmd := server.NewCommandStartCozyServer(ctx, options)
code := cli.Run(cmd)
os.Exit(code)
}

File diff suppressed because it is too large Load Diff

View File

@@ -81,6 +81,7 @@ modules/340-monitoring-kubernetes/monitoring/grafana-dashboards//main/capacity-p
modules/340-monitoring-kubernetes/monitoring/grafana-dashboards//flux/flux-control-plane.json
modules/340-monitoring-kubernetes/monitoring/grafana-dashboards//flux/flux-stats.json
modules/340-monitoring-kubernetes/monitoring/grafana-dashboards//kafka/strimzi-kafka.json
modules/340-monitoring-kubernetes/monitoring/grafana-dashboards//seaweedfs/seaweedfs.json
modules/340-monitoring-kubernetes/monitoring/grafana-dashboards//goldpinger/goldpinger.json
EOT

47
hack/e2e-apps/bucket.bats Normal file
View File

@@ -0,0 +1,47 @@
#!/usr/bin/env bats
@test "Create and Verify Seeweedfs Bucket" {
# Create the bucket resource
name='test'
kubectl apply -f - <<EOF
apiVersion: apps.cozystack.io/v1alpha1
kind: Bucket
metadata:
name: ${name}
namespace: tenant-test
spec: {}
EOF
# Wait for the bucket to be ready
kubectl -n tenant-test wait hr bucket-${name} --timeout=100s --for=condition=ready
kubectl -n tenant-test wait bucketclaims.objectstorage.k8s.io bucket-${name} --timeout=300s --for=jsonpath='{.status.bucketReady}'
kubectl -n tenant-test wait bucketaccesses.objectstorage.k8s.io bucket-${name} --timeout=300s --for=jsonpath='{.status.accessGranted}'
# Get and decode credentials
kubectl -n tenant-test get secret bucket-${name} -ojsonpath='{.data.BucketInfo}' | base64 -d > bucket-test-credentials.json
# Get credentials from the secret
ACCESS_KEY=$(jq -r '.spec.secretS3.accessKeyID' bucket-test-credentials.json)
SECRET_KEY=$(jq -r '.spec.secretS3.accessSecretKey' bucket-test-credentials.json)
BUCKET_NAME=$(jq -r '.spec.bucketName' bucket-test-credentials.json)
# Start port-forwarding
bash -c 'timeout 100s kubectl port-forward service/seaweedfs-s3 -n tenant-root 8333:8333 > /dev/null 2>&1 &'
# Wait for port-forward to be ready
timeout 30 sh -ec 'until nc -z localhost 8333; do sleep 1; done'
# Set up MinIO alias with error handling
mc alias set local https://localhost:8333 $ACCESS_KEY $SECRET_KEY --insecure
# Upload file to bucket
mc cp bucket-test-credentials.json $BUCKET_NAME/bucket-test-credentials.json
# Verify file was uploaded
mc ls $BUCKET_NAME/bucket-test-credentials.json
# Clean up uploaded file
mc rm $BUCKET_NAME/bucket-test-credentials.json
kubectl -n tenant-test delete bucket.apps.cozystack.io ${name}
}

View File

@@ -123,10 +123,10 @@ EOF
@test "Configure Tenant and wait for applications" {
# Patch root tenant and wait for its releases
kubectl patch tenants/root -n tenant-root --type merge -p '{"spec":{"host":"example.org","ingress":true,"monitoring":true,"etcd":true,"isolated":true}}'
kubectl patch tenants/root -n tenant-root --type merge -p '{"spec":{"host":"example.org","ingress":true,"monitoring":true,"etcd":true,"isolated":true, "seaweedfs": true}}'
timeout 60 sh -ec 'until kubectl get hr -n tenant-root etcd ingress monitoring tenant-root >/dev/null 2>&1; do sleep 1; done'
kubectl wait hr/etcd hr/ingress hr/tenant-root -n tenant-root --timeout=2m --for=condition=ready
timeout 60 sh -ec 'until kubectl get hr -n tenant-root etcd ingress monitoring seaweedfs tenant-root >/dev/null 2>&1; do sleep 1; done'
kubectl wait hr/etcd hr/ingress hr/tenant-root hr/seaweedfs -n tenant-root --timeout=4m --for=condition=ready
if ! kubectl wait hr/monitoring -n tenant-root --timeout=2m --for=condition=ready; then
flux reconcile hr monitoring -n tenant-root --force

View File

@@ -32,6 +32,10 @@ kube::codegen::gen_helpers \
--boilerplate "${SCRIPT_ROOT}/hack/boilerplate.go.txt" \
"${SCRIPT_ROOT}/pkg/apis"
kube::codegen::gen_helpers \
--boilerplate "${SCRIPT_ROOT}/hack/boilerplate.go.txt" \
"${SCRIPT_ROOT}/api"
if [[ -n "${API_KNOWN_VIOLATIONS_DIR:-}" ]]; then
report_filename="${API_KNOWN_VIOLATIONS_DIR}/cozystack_api_violation_exceptions.list"
if [[ "${UPDATE_API_KNOWN_VIOLATIONS:-}" == "true" ]]; then

View File

@@ -1 +1 @@
ghcr.io/cozystack/cozystack/nginx-cache:0.6.1@sha256:e0a07082bb6fc6aeaae2315f335386f1705a646c72f9e0af512aebbca5cb2b15
ghcr.io/cozystack/cozystack/nginx-cache:0.6.1@sha256:b7633717cd7449c0042ae92d8ca9b36e4d69566561f5c7d44e21058e7d05c6d5

View File

@@ -16,7 +16,7 @@ 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.26.0
version: 0.26.3
# 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

View File

@@ -1 +1 @@
ghcr.io/cozystack/cozystack/cluster-autoscaler:0.26.0@sha256:3a8170433e1632e5cc2b6d9db34d0605e8e6c63c158282c38450415e700e932e
ghcr.io/cozystack/cozystack/cluster-autoscaler:0.26.2@sha256:3a8170433e1632e5cc2b6d9db34d0605e8e6c63c158282c38450415e700e932e

View File

@@ -1 +1 @@
ghcr.io/cozystack/cozystack/kubevirt-cloud-provider:0.26.0@sha256:49843a0b670eab061627e48df338b2b8bc9f577dc2cfd4c2ed4071e02e64b424
ghcr.io/cozystack/cozystack/kubevirt-cloud-provider:0.26.2@sha256:5335c044313b69ee13b30ca4941687e509005e55f4ae25723861edbf2fbd6dd2

View File

@@ -21,6 +21,6 @@ RUN go mod vendor
RUN CGO_ENABLED=0 go build -mod=vendor -ldflags="-s -w" -o bin/kubevirt-cloud-controller-manager ./cmd/kubevirt-cloud-controller-manager
FROM registry.access.redhat.com/ubi9/ubi-micro
FROM scratch
COPY --from=builder /go/src/kubevirt.io/cloud-provider-kubevirt/bin/kubevirt-cloud-controller-manager /bin/kubevirt-cloud-controller-manager
ENTRYPOINT [ "/bin/kubevirt-cloud-controller-manager" ]

View File

@@ -1 +1 @@
ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.26.0@sha256:445c2727b04ac68595b43c988ff17b3d69a7b22b0644fde3b10c65b47a7bc036
ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.26.2@sha256:761e7235ff9cb7f6f223f00954943e6a5af32ed6624ee592a8610122f96febb0

View File

@@ -35,6 +35,8 @@ spec:
storageClass: "{{ . }}"
{{- end }}
dependsOn:
- name: {{ .Release.Name }}-vsnap-crd
namespace: {{ .Release.Namespace }}
{{- if lookup "helm.toolkit.fluxcd.io/v2" "HelmRelease" .Release.Namespace .Release.Name }}
- name: {{ .Release.Name }}
namespace: {{ .Release.Namespace }}

View File

@@ -4,6 +4,7 @@
{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }}
{{- $targetTenant := index $myNS.metadata.annotations "namespace.cozystack.io/monitoring" }}
vertical-pod-autoscaler:
vpaForVPA: false
recommender:
extraArgs:
container-name-label: container

View File

@@ -1,16 +1,16 @@
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: {{ .Release.Name }}-volumesnapshot-crd-for-tenant-k8s
name: {{ .Release.Name }}-vsnap-crd
labels:
cozystack.io/repository: system
cozystack.io/target-cluster-name: {{ .Release.Name }}
spec:
interval: 5m
releaseName: volumesnapshot-crd-for-tenant-k8s
releaseName: vsnap-crd
chart:
spec:
chart: cozy-volumesnapshot-crd-for-tenant-k8s
chart: cozy-vsnap-crd
reconcileStrategy: Revision
sourceRef:
kind: HelmRepository
@@ -21,8 +21,8 @@ spec:
secretRef:
name: {{ .Release.Name }}-admin-kubeconfig
key: super-admin.svc
targetNamespace: cozy-volumesnapshot-crd-for-tenant-k8s
storageNamespace: cozy-volumesnapshot-crd-for-tenant-k8s
targetNamespace: cozy-vsnap-crd
storageNamespace: cozy-vsnap-crd
install:
createNamespace: true
remediation:

View File

@@ -39,6 +39,11 @@ rules:
resources:
- workloadmonitors
verbs: ["get", "list", "watch"]
- apiGroups:
- core.cozystack.io
resources:
- tenantsecrets
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
@@ -188,6 +193,11 @@ rules:
resources:
- workloadmonitors
verbs: ["get", "list", "watch"]
- apiGroups:
- core.cozystack.io
resources:
- tenantsecrets
verbs: ["get", "list", "watch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
@@ -279,6 +289,11 @@ rules:
resources:
- workloadmonitors
verbs: ["get", "list", "watch"]
- apiGroups:
- core.cozystack.io
resources:
- tenantsecrets
verbs: ["get", "list", "watch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
@@ -346,6 +361,11 @@ rules:
resources:
- workloadmonitors
verbs: ["get", "list", "watch"]
- apiGroups:
- core.cozystack.io
resources:
- tenantsecrets
verbs: ["get", "list", "watch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1

View File

@@ -61,7 +61,10 @@ kubernetes 0.24.0 62cb694d
kubernetes 0.25.0 70f82667
kubernetes 0.25.1 acd4663a
kubernetes 0.25.2 08cb7c0f
kubernetes 0.26.0 HEAD
kubernetes 0.26.0 9584e5f5
kubernetes 0.26.1 0e47e1e8
kubernetes 0.26.2 8ddbe32e
kubernetes 0.26.3 HEAD
mysql 0.1.0 263e47be
mysql 0.2.0 c24a103f
mysql 0.3.0 53f2365e
@@ -172,7 +175,8 @@ virtual-machine 0.10.2 632224a3
virtual-machine 0.11.0 4369b031
virtual-machine 0.12.0 acd4663a
virtual-machine 0.12.1 909208ba
virtual-machine 0.12.2 HEAD
virtual-machine 0.12.2 8ddbe32e
virtual-machine 0.12.3 HEAD
vm-disk 0.1.0 d971f2ff
vm-disk 0.1.1 6130f43d
vm-disk 0.1.2 632224a3
@@ -191,7 +195,8 @@ vm-instance 0.7.2 632224a3
vm-instance 0.8.0 4369b031
vm-instance 0.9.0 acd4663a
vm-instance 0.10.0 909208ba
vm-instance 0.10.1 HEAD
vm-instance 0.10.1 8ddbe32e
vm-instance 0.10.2 HEAD
vpn 0.1.0 263e47be
vpn 0.2.0 53f2365e
vpn 0.3.0 6c5cf5bf

View File

@@ -17,7 +17,7 @@ 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.12.2
version: 0.12.3
# 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

View File

@@ -3,10 +3,10 @@ include ../../../scripts/package.mk
generate:
readme-generator-for-helm -v values.yaml -s values.schema.json -r README.md
yq -o json -i '.properties.gpus.items.type = "object" | .properties.gpus.default = []' values.schema.json
INSTANCE_TYPES=$$(yq e '.metadata.name' -o=json -r ../../system/kubevirt-instancetypes/templates/instancetypes.yaml | yq 'split(" ") | . + [""]' -o json) \
&& yq -i -o json ".properties.instanceType.optional=true | .properties.instanceType.enum = $${INSTANCE_TYPES}" values.schema.json
# INSTANCE_TYPES=$$(yq e '.metadata.name' -o=json -r ../../system/kubevirt-instancetypes/templates/instancetypes.yaml | yq 'split(" ") | . + [""]' -o json) \
# && yq -i -o json ".properties.instanceType.enum = $${INSTANCE_TYPES}" values.schema.json
PREFERENCES=$$(yq e '.metadata.name' -o=json -r ../../system/kubevirt-instancetypes/templates/preferences.yaml | yq 'split(" ") | . + [""]' -o json) \
&& yq -i -o json ".properties.instanceProfile.optional=true | .properties.instanceProfile.enum = $${PREFERENCES}" values.schema.json
&& yq -i -o json ".properties.instanceProfile.enum = $${PREFERENCES}" values.schema.json
yq -i -o json '.properties.externalPorts.items.type = "integer"' values.schema.json
yq -i -o json '.properties.systemDisk.properties.image.enum = ["ubuntu", "cirros", "alpine", "fedora", "talos"]' values.schema.json
yq -i -o json '.properties.externalMethod.enum = ["PortList", "WholeIP"]' values.schema.json

View File

@@ -44,7 +44,6 @@
"default": "ubuntu",
"description": "Virtual Machine preferences profile",
"type": "string",
"optional": true,
"enum": [
"alpine",
"centos.7",
@@ -94,59 +93,7 @@
"instanceType": {
"default": "u1.medium",
"description": "Virtual Machine instance type",
"type": "string",
"optional": true,
"enum": [
"cx1.2xlarge",
"cx1.4xlarge",
"cx1.8xlarge",
"cx1.large",
"cx1.medium",
"cx1.xlarge",
"gn1.2xlarge",
"gn1.4xlarge",
"gn1.8xlarge",
"gn1.xlarge",
"m1.2xlarge",
"m1.4xlarge",
"m1.8xlarge",
"m1.large",
"m1.xlarge",
"n1.2xlarge",
"n1.4xlarge",
"n1.8xlarge",
"n1.large",
"n1.medium",
"n1.xlarge",
"o1.2xlarge",
"o1.4xlarge",
"o1.8xlarge",
"o1.large",
"o1.medium",
"o1.micro",
"o1.nano",
"o1.small",
"o1.xlarge",
"rt1.2xlarge",
"rt1.4xlarge",
"rt1.8xlarge",
"rt1.large",
"rt1.medium",
"rt1.micro",
"rt1.small",
"rt1.xlarge",
"u1.2xlarge",
"u1.2xmedium",
"u1.4xlarge",
"u1.8xlarge",
"u1.large",
"u1.medium",
"u1.micro",
"u1.nano",
"u1.small",
"u1.xlarge",
""
]
"type": "string"
},
"resources": {
"properties": {

View File

@@ -17,7 +17,7 @@ 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.10.1
version: 0.10.2
# 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

View File

@@ -4,9 +4,9 @@ generate:
readme-generator-for-helm -v values.yaml -s values.schema.json -r README.md
yq -o json -i '.properties.disks.items.type = "object" | .properties.disks.default = []' values.schema.json
yq -o json -i '.properties.gpus.items.type = "object" | .properties.gpus.default = []' values.schema.json
INSTANCE_TYPES=$$(yq e '.metadata.name' -o=json -r ../../system/kubevirt-instancetypes/templates/instancetypes.yaml | yq 'split(" ") | . + [""]' -o json) \
&& yq -i -o json ".properties.instanceType.optional=true | .properties.instanceType.enum = $${INSTANCE_TYPES}" values.schema.json
#INSTANCE_TYPES=$$(yq e '.metadata.name' -o=json -r ../../system/kubevirt-instancetypes/templates/instancetypes.yaml | yq 'split(" ") | . + [""]' -o json) \
# && yq -i -o json ".properties.instanceType.enum = $${INSTANCE_TYPES}" values.schema.json
PREFERENCES=$$(yq e '.metadata.name' -o=json -r ../../system/kubevirt-instancetypes/templates/preferences.yaml | yq 'split(" ") | . + [""]' -o json) \
&& yq -i -o json ".properties.instanceProfile.optional=true | .properties.instanceProfile.enum = $${PREFERENCES}" values.schema.json
&& yq -i -o json ".properties.instanceProfile.enum = $${PREFERENCES}" values.schema.json
yq -i -o json '.properties.externalPorts.items.type = "integer"' values.schema.json
yq -i -o json '.properties.externalMethod.enum = ["PortList", "WholeIP"]' values.schema.json

View File

@@ -52,7 +52,6 @@
"default": "ubuntu",
"description": "Virtual Machine preferences profile",
"type": "string",
"optional": true,
"enum": [
"alpine",
"centos.7",
@@ -102,59 +101,7 @@
"instanceType": {
"default": "u1.medium",
"description": "Virtual Machine instance type",
"type": "string",
"optional": true,
"enum": [
"cx1.2xlarge",
"cx1.4xlarge",
"cx1.8xlarge",
"cx1.large",
"cx1.medium",
"cx1.xlarge",
"gn1.2xlarge",
"gn1.4xlarge",
"gn1.8xlarge",
"gn1.xlarge",
"m1.2xlarge",
"m1.4xlarge",
"m1.8xlarge",
"m1.large",
"m1.xlarge",
"n1.2xlarge",
"n1.4xlarge",
"n1.8xlarge",
"n1.large",
"n1.medium",
"n1.xlarge",
"o1.2xlarge",
"o1.4xlarge",
"o1.8xlarge",
"o1.large",
"o1.medium",
"o1.micro",
"o1.nano",
"o1.small",
"o1.xlarge",
"rt1.2xlarge",
"rt1.4xlarge",
"rt1.8xlarge",
"rt1.large",
"rt1.medium",
"rt1.micro",
"rt1.small",
"rt1.xlarge",
"u1.2xlarge",
"u1.2xmedium",
"u1.4xlarge",
"u1.8xlarge",
"u1.large",
"u1.medium",
"u1.micro",
"u1.nano",
"u1.small",
"u1.xlarge",
""
]
"type": "string"
},
"resources": {
"properties": {

View File

@@ -1,2 +1,2 @@
cozystack:
image: ghcr.io/cozystack/cozystack/installer:v0.35.0-alpha.1@sha256:c50451e26a1a2a9f8962e26f6ab668b71b95186f53c1ae84118733e2cd464293
image: ghcr.io/cozystack/cozystack/installer:v0.35.0-alpha.3@sha256:b43615350697dbbc377d31152b290722c2bba7a053fd7c69403d666e6c7d53ee

View File

@@ -19,6 +19,7 @@ RUN curl -sSL "https://github.com/mikefarah/yq/releases/download/v4.44.3/yq_${TA
&& chmod +x /usr/local/bin/yq
RUN curl -sSL "https://fluxcd.io/install.sh" | bash
RUN curl -sSL "https://github.com/cozystack/cozypkg/raw/refs/heads/main/hack/install.sh" | sh -s -- -v "${COZYPKG_VERSION}"
RUN curl https://dl.min.io/client/mc/release/${TARGETOS}-${TARGETARCH}/mc --create-dirs -o /usr/local/bin/mc \
&& chmod +x /usr/local/bin/mc
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]

View File

@@ -1,2 +1,2 @@
e2e:
image: ghcr.io/cozystack/cozystack/e2e-sandbox:v0.35.0-alpha.1@sha256:ea73a2aeeac810be8eaee636aba6d6d10051772297ee76b6ce28a2aa7aa6a7f4
image: ghcr.io/cozystack/cozystack/e2e-sandbox:v0.35.0-alpha.3@sha256:cd6d65230150171c0e3934f71fcc270718f2bfec7509989b9d4d996ddef916d9

View File

@@ -1 +1 @@
ghcr.io/cozystack/cozystack/matchbox:v0.35.0-alpha.1@sha256:103e7c66ba47caee2126eca2d4b40e67041d4a3e6b729945b4dfc55decda74e7
ghcr.io/cozystack/cozystack/matchbox:v0.35.0-alpha.3@sha256:043051d7c368b73943051b51bacfb3e383541b53190f74452d552ea2f30e420e

View File

@@ -3,4 +3,4 @@ name: monitoring
description: Monitoring and observability stack
icon: /logos/monitoring.svg
type: application
version: 1.12.0
version: 1.12.1

View File

@@ -37,4 +37,5 @@ flux/flux-stats
kafka/strimzi-kafka
goldpinger/goldpinger
clickhouse/altinity-clickhouse-operator-dashboard
storage/linstor
storage/linstor
seaweedfs/seaweedfs

View File

@@ -1 +1 @@
ghcr.io/cozystack/cozystack/grafana:1.12.0@sha256:c63978e1ed0304e8518b31ddee56c4e8115541b997d8efbe1c0a74da57140399
ghcr.io/cozystack/cozystack/grafana:1.12.1@sha256:c63978e1ed0304e8518b31ddee56c4e8115541b997d8efbe1c0a74da57140399

View File

@@ -16,7 +16,7 @@ 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.5.0
version: 0.6.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

View File

@@ -4,14 +4,15 @@
### Common parameters
| Name | Description | Value |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------ | --------------- |
| `host` | The hostname used to access the SeaweedFS externally (defaults to 's3' subdomain for the tenant host). | `""` |
| `topology` | The topology of the SeaweedFS cluster. (allowed values: Simple, MultiZone, Client) | `Simple` |
| `replicationFactor` | The number of replicas for each volume in the SeaweedFS cluster. | `2` |
| `replicas` | Persistent Volume size for SeaweedFS | `2` |
| `size` | Persistent Volume size | `10Gi` |
| `storageClass` | StorageClass used to store the data | `""` |
| `zones` | A map of zones for MultiZone topology. Each zone can have its own number of replicas and size. | `{}` |
| `filer.external` | Enable external access to the SeaweedFS filer from outside the cluster. Use this when `topology` is not set to `Client`. | `false` |
| `remoteEndpoint` | The endpoint of the remote filer GRPC service. Used when `topology` is set to `Client`. | `1.2.3.4:18888` |
| Name | Description | Value |
| ------------------- | ------------------------------------------------------------------------------------------------------ | -------- |
| `host` | The hostname used to access the SeaweedFS externally (defaults to 's3' subdomain for the tenant host). | `""` |
| `topology` | The topology of the SeaweedFS cluster. (allowed values: Simple, MultiZone, Client) | `Simple` |
| `replicationFactor` | The number of replicas for each volume in the SeaweedFS cluster. | `2` |
| `replicas` | Persistent Volume size for SeaweedFS | `2` |
| `size` | Persistent Volume size | `10Gi` |
| `storageClass` | StorageClass used to store the data | `""` |
| `zones` | A map of zones for MultiZone topology. Each zone can have its own number of replicas and size. | `{}` |
| `filer.grpcHost` | The hostname used to expose or access the filer service externally. | `""` |
| `filer.grpcPort` | The port used to access the filer service externally. | `443` |
| `filer.whitelist` | A list of IP addresses or CIDR ranges that are allowed to access the filer service. | `[]` |

View File

@@ -1 +1 @@
ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.35.0-alpha.1@sha256:e4f9a7302285ea9febeb28fc2fa97cb7c01bb91e602f975c31aad1fe46f778f7
ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.35.0-alpha.3@sha256:4a67ec40c13bf912151957dc0e7409f7e01a2859905285c98c20baae7b667ae2

View File

@@ -0,0 +1 @@
ghcr.io/seaweedfs/seaweedfs-cosi-driver:v0.2.0

View File

@@ -35,7 +35,7 @@ spec:
spec:
containers:
- name: seaweedfs-cosi-driver
image: ghcr.io/seaweedfs/seaweedfs-cosi-driver:v0.1.2
image: "{{ $.Files.Get "images/seaweedfs-cosi-driver.tag" | trim }}"
imagePullPolicy: IfNotPresent
env:
- name: DRIVERNAME
@@ -43,7 +43,7 @@ spec:
- name: ENDPOINT
value: https://{{ .Values.host | default (printf "s3.%s" $host) }}
- name: SEAWEEDFS_FILER
value: {{ .Values.remoteEndpoint }}
value: "{{ .Values.filer.grpcHost }}:{{ .Values.filer.grpcPort }}"
- name: WEED_GRPC_CLIENT_KEY
value: /usr/local/share/ca-certificates/client/tls.key
- name: WEED_GRPC_CLIENT_CERT

View File

@@ -0,0 +1,44 @@
{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }}
{{- $issuerType := (index $cozyConfig.data "clusterissuer") | default "http01" }}
{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }}
{{- $ingress := index $myNS.metadata.annotations "namespace.cozystack.io/ingress" }}
{{- $host := index $myNS.metadata.annotations "namespace.cozystack.io/host" }}
{{- if and (not (eq .Values.topology "Client")) (.Values.filer.grpcHost) }}
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/backend-protocol: GRPCS
nginx.ingress.kubernetes.io/ssl-passthrough: "true"
nginx.ingress.kubernetes.io/whitelist-source-range: "{{ join "," (.Values.filer.whitelist | default "0.0.0.0/32") }}"
name: seaweedfs-filer-external
spec:
ingressClassName: tenant-root
rules:
- host: {{ .Values.filer.grpcHost | default (printf "filer.%s" $host) }}
http:
paths:
- backend:
service:
name: {{ $.Release.Name }}-filer-external
port:
number: 18888
path: /
pathType: ImplementationSpecific
---
apiVersion: v1
kind: Service
metadata:
name: {{ $.Release.Name }}-filer-external
spec:
ports:
- name: swfs-filer-grpc
port: 18888
protocol: TCP
targetPort: 18888
selector:
app.kubernetes.io/component: filer
app.kubernetes.io/name: {{ $.Release.Name }}
{{- end }}

View File

@@ -2,8 +2,8 @@
{{- if not (has .Values.topology (list "Simple" "MultiZone" "Client")) }}
{{- fail "Invalid value for .Values.topology. Must be one of 'Simple', 'MultiZone' or 'Client'." }}
{{- end }}
{{- if and (eq .Values.topology "Client") (not .Values.remoteEndpoint) }}
{{- fail "When topology is 'Client', .Values.remoteEndpoint must be set to a valid remote filer GRPC service endpoint." }}
{{- if and (eq .Values.topology "Client") (not .Values.filer.grpcHost) }}
{{- fail "When topology is 'Client', .Values.filer.grpcHost must be set to a valid remote filer GRPC service endpoint." }}
{{- end }}
{{- if lt (int .Values.replicationFactor) 1 }}
{{- fail "Invalid value for .Values.replicationFactor. Must be at least 1." }}

View File

@@ -1,18 +0,0 @@
{{- if and (not (eq .Values.topology "Client")) (.Values.filer.external) }}
---
apiVersion: v1
kind: Service
metadata:
name: {{ $.Release.Name }}-filer-external
spec:
type: LoadBalancer
externalTrafficPolicy: Local
ports:
- name: swfs-filer-grpc
port: 18888
protocol: TCP
targetPort: 18888
selector:
app.kubernetes.io/component: filer
app.kubernetes.io/name: {{ $.Release.Name }}
{{- end }}

View File

@@ -2,10 +2,21 @@
"properties": {
"filer": {
"properties": {
"external": {
"default": false,
"description": "Enable external access to the SeaweedFS filer from outside the cluster. Use this when `topology` is not set to `Client`.",
"type": "boolean"
"grpcHost": {
"default": "",
"description": "The hostname used to expose or access the filer service externally.",
"type": "string"
},
"grpcPort": {
"default": 443,
"description": "The port used to access the filer service externally.",
"type": "number"
},
"whitelist": {
"default": [],
"description": "A list of IP addresses or CIDR ranges that are allowed to access the filer service.",
"items": {},
"type": "array"
}
},
"type": "object"
@@ -15,11 +26,6 @@
"description": "The hostname used to access the SeaweedFS externally (defaults to 's3' subdomain for the tenant host).",
"type": "string"
},
"remoteEndpoint": {
"default": "1.2.3.4:18888",
"description": "The endpoint of the remote filer GRPC service. Used when `topology` is set to `Client`.",
"type": "string"
},
"replicas": {
"default": 2,
"description": "Persistent Volume size for SeaweedFS",

View File

@@ -32,9 +32,10 @@ storageClass: ""
## size: 10Gi
zones: {}
## @param filer.external Enable external access to the SeaweedFS filer from outside the cluster. Use this when `topology` is not set to `Client`.
## @param filer.grpcHost The hostname used to expose or access the filer service externally.
## @param filer.grpcPort The port used to access the filer service externally.
## @param filer.whitelist A list of IP addresses or CIDR ranges that are allowed to access the filer service.
filer:
external: false
## @param remoteEndpoint The endpoint of the remote filer GRPC service. Used when `topology` is set to `Client`.
remoteEndpoint: "1.2.3.4:18888"
grpcHost: ""
grpcPort: 443
whitelist: []

View File

@@ -47,11 +47,13 @@ monitoring 1.9.2 f9f8bb2f
monitoring 1.10.0 632224a3
monitoring 1.10.1 8c86905b
monitoring 1.11.0 4369b031
monitoring 1.12.0 HEAD
monitoring 1.12.0 0e47e1e8
monitoring 1.12.1 HEAD
seaweedfs 0.1.0 71514249
seaweedfs 0.2.0 5fb9cfe3
seaweedfs 0.2.1 fde4bcfa
seaweedfs 0.3.0 45a7416c
seaweedfs 0.4.0 632224a3
seaweedfs 0.4.1 8c86905b
seaweedfs 0.5.0 HEAD
seaweedfs 0.5.0 9584e5f5
seaweedfs 0.6.0 HEAD

View File

@@ -1 +1 @@
ghcr.io/cozystack/cozystack/s3manager:v0.5.0@sha256:34db8c950f14a3e2742b7c31bd3c6a1fe631c9b398caac611ed5cfdac5769d36
ghcr.io/cozystack/cozystack/s3manager:v0.5.0@sha256:b39a00543d28cb72617bc50c7a9f873d65c3cd34114d9690cf044f7fac66c8da

View File

@@ -11,3 +11,17 @@ spec:
name: cozystack-api
namespace: cozy-system
version: v1alpha1
---
apiVersion: apiregistration.k8s.io/v1
kind: APIService
metadata:
name: v1alpha1.core.cozystack.io
spec:
insecureSkipTLSVerify: true
group: core.cozystack.io
groupPriorityMinimum: 1000
versionPriority: 15
service:
name: cozystack-api
namespace: cozy-system
version: v1alpha1

View File

@@ -1,353 +0,0 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: cozystack-api
namespace: cozy-system
data:
config.yaml: |
resources:
- application:
kind: Bucket
singular: bucket
plural: buckets
openAPISchema: {{ .Files.Get "openapi-schemas/bucket.json" | fromJson | toJson | quote }}
release:
prefix: bucket-
labels:
cozystack.io/ui: "true"
chart:
name: bucket
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
- application:
kind: ClickHouse
singular: clickhouse
plural: clickhouses
openAPISchema: {{ .Files.Get "openapi-schemas/clickhouse.json" | fromJson | toJson | quote }}
release:
prefix: clickhouse-
labels:
cozystack.io/ui: "true"
chart:
name: clickhouse
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
- application:
kind: HTTPCache
singular: httpcache
plural: httpcaches
openAPISchema: {{ .Files.Get "openapi-schemas/http-cache.json" | fromJson | toJson | quote }}
release:
prefix: http-cache-
labels:
cozystack.io/ui: "true"
chart:
name: http-cache
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
- application:
kind: NATS
singular: nats
plural: natses
openAPISchema: {{ .Files.Get "openapi-schemas/nats.json" | fromJson | toJson | quote }}
release:
prefix: nats-
labels:
cozystack.io/ui: "true"
chart:
name: nats
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
- application:
kind: TCPBalancer
singular: tcpbalancer
plural: tcpbalancers
openAPISchema: {{ .Files.Get "openapi-schemas/tcp-balancer.json" | fromJson | toJson | quote }}
release:
prefix: tcp-balancer-
labels:
cozystack.io/ui: "true"
chart:
name: tcp-balancer
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
- application:
kind: VirtualMachine
singular: virtualmachine
plural: virtualmachines
openAPISchema: {{ .Files.Get "openapi-schemas/virtual-machine.json" | fromJson | toJson | quote }}
release:
prefix: virtual-machine-
labels:
cozystack.io/ui: "true"
chart:
name: virtual-machine
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
- application:
kind: VPN
singular: vpn
plural: vpns
openAPISchema: {{ .Files.Get "openapi-schemas/vpn.json" | fromJson | toJson | quote }}
release:
prefix: vpn-
labels:
cozystack.io/ui: "true"
chart:
name: vpn
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
- application:
kind: MySQL
singular: mysql
plural: mysqls
openAPISchema: {{ .Files.Get "openapi-schemas/mysql.json" | fromJson | toJson | quote }}
release:
prefix: mysql-
labels:
cozystack.io/ui: "true"
chart:
name: mysql
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
- application:
kind: Tenant
singular: tenant
plural: tenants
openAPISchema: {{ .Files.Get "openapi-schemas/tenant.json" | fromJson | toJson | quote }}
release:
prefix: tenant-
labels:
cozystack.io/ui: "true"
chart:
name: tenant
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
- application:
kind: Kubernetes
singular: kubernetes
plural: kuberneteses
openAPISchema: {{ .Files.Get "openapi-schemas/kubernetes.json" | fromJson | toJson | quote }}
release:
prefix: kubernetes-
labels:
cozystack.io/ui: "true"
chart:
name: kubernetes
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
- application:
kind: Redis
singular: redis
plural: redises
openAPISchema: {{ .Files.Get "openapi-schemas/redis.json" | fromJson | toJson | quote }}
release:
prefix: redis-
labels:
cozystack.io/ui: "true"
chart:
name: redis
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
- application:
kind: RabbitMQ
singular: rabbitmq
plural: rabbitmqs
openAPISchema: {{ .Files.Get "openapi-schemas/rabbitmq.json" | fromJson | toJson | quote }}
release:
prefix: rabbitmq-
labels:
cozystack.io/ui: "true"
chart:
name: rabbitmq
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
- application:
kind: Postgres
singular: postgres
plural: postgreses
openAPISchema: {{ .Files.Get "openapi-schemas/postgres.json" | fromJson | toJson | quote }}
release:
prefix: postgres-
labels:
cozystack.io/ui: "true"
chart:
name: postgres
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
- application:
kind: FerretDB
singular: ferretdb
plural: ferretdb
openAPISchema: {{ .Files.Get "openapi-schemas/ferretdb.json" | fromJson | toJson | quote }}
release:
prefix: ferretdb-
labels:
cozystack.io/ui: "true"
chart:
name: ferretdb
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
- application:
kind: Kafka
singular: kafka
plural: kafkas
openAPISchema: {{ .Files.Get "openapi-schemas/kafka.json" | fromJson | toJson | quote }}
release:
prefix: kafka-
labels:
cozystack.io/ui: "true"
chart:
name: kafka
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
- application:
kind: VMDisk
plural: vmdisks
singular: vmdisk
openAPISchema: {{ .Files.Get "openapi-schemas/vm-disk.json" | fromJson | toJson | quote }}
release:
prefix: vm-disk-
labels:
cozystack.io/ui: "true"
chart:
name: vm-disk
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
- application:
kind: VMInstance
plural: vminstances
singular: vminstance
openAPISchema: {{ .Files.Get "openapi-schemas/vm-instance.json" | fromJson | toJson | quote }}
release:
prefix: vm-instance-
labels:
cozystack.io/ui: "true"
chart:
name: vm-instance
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
- application:
kind: Monitoring
plural: monitorings
singular: monitoring
openAPISchema: {{ .Files.Get "openapi-schemas/monitoring.json" | fromJson | toJson | quote }}
release:
prefix: ""
labels:
cozystack.io/ui: "true"
chart:
name: monitoring
sourceRef:
kind: HelmRepository
name: cozystack-extra
namespace: cozy-public
- application:
kind: Etcd
plural: etcds
singular: etcd
openAPISchema: {{ .Files.Get "openapi-schemas/etcd.json" | fromJson | toJson | quote }}
release:
prefix: ""
labels:
cozystack.io/ui: "true"
chart:
name: etcd
sourceRef:
kind: HelmRepository
name: cozystack-extra
namespace: cozy-public
- application:
kind: Ingress
plural: ingresses
singular: ingress
openAPISchema: {{ .Files.Get "openapi-schemas/ingress.json" | fromJson | toJson | quote }}
release:
prefix: ""
labels:
cozystack.io/ui: "true"
chart:
name: ingress
sourceRef:
kind: HelmRepository
name: cozystack-extra
namespace: cozy-public
- application:
kind: SeaweedFS
plural: seaweedfses
singular: seaweedfs
openAPISchema: {{ .Files.Get "openapi-schemas/seaweedfs.json" | fromJson | toJson | quote }}
release:
prefix: ""
labels:
cozystack.io/ui: "true"
chart:
name: seaweedfs
sourceRef:
kind: HelmRepository
name: cozystack-extra
namespace: cozy-public
- application:
kind: BootBox
plural: bootboxes
singular: bootbox
openAPISchema: {{ .Files.Get "openapi-schemas/bootbox.json" | fromJson | toJson | quote }}
release:
prefix: ""
labels:
cozystack.io/ui: "true"
chart:
name: bootbox
sourceRef:
kind: HelmRepository
name: cozystack-extra
namespace: cozy-public
- application:
kind: Info
plural: infos
singular: info
openAPISchema: {{ .Files.Get "openapi-schemas/info.json" | fromJson | toJson | quote }}
release:
prefix: ""
labels:
cozystack.io/ui: "true"
chart:
name: info
sourceRef:
kind: HelmRepository
name: cozystack-extra
namespace: cozy-public

View File

@@ -0,0 +1,505 @@
apiVersion: cozystack.io/v1alpha1
kind: CozystackResourceDefinition
metadata:
name: bucket
spec:
application:
kind: Bucket
singular: bucket
plural: buckets
openAPISchema: |
{{- .Files.Get "openapi-schemas/bucket.json" | fromJson | toJson | nindent 6 }}
release:
prefix: bucket-
labels:
cozystack.io/ui: "true"
chart:
name: bucket
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
---
apiVersion: cozystack.io/v1alpha1
kind: CozystackResourceDefinition
metadata:
name: clickhouse
spec:
application:
kind: ClickHouse
singular: clickhouse
plural: clickhouses
openAPISchema: |
{{- .Files.Get "openapi-schemas/clickhouse.json" | fromJson | toJson | nindent 6 }}
release:
prefix: clickhouse-
labels:
cozystack.io/ui: "true"
chart:
name: clickhouse
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
---
apiVersion: cozystack.io/v1alpha1
kind: CozystackResourceDefinition
metadata:
name: httpcache
spec:
application:
kind: HTTPCache
singular: httpcache
plural: httpcaches
openAPISchema: |
{{- .Files.Get "openapi-schemas/http-cache.json" | fromJson | toJson | nindent 6 }}
release:
prefix: http-cache-
labels:
cozystack.io/ui: "true"
chart:
name: http-cache
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
---
apiVersion: cozystack.io/v1alpha1
kind: CozystackResourceDefinition
metadata:
name: nats
spec:
application:
kind: NATS
singular: nats
plural: natses
openAPISchema: |
{{- .Files.Get "openapi-schemas/nats.json" | fromJson | toJson | nindent 6 }}
release:
prefix: nats-
labels:
cozystack.io/ui: "true"
chart:
name: nats
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
---
apiVersion: cozystack.io/v1alpha1
kind: CozystackResourceDefinition
metadata:
name: tcpbalancer
spec:
application:
kind: TCPBalancer
singular: tcpbalancer
plural: tcpbalancers
openAPISchema: |
{{- .Files.Get "openapi-schemas/tcp-balancer.json" | fromJson | toJson | nindent 6 }}
release:
prefix: tcp-balancer-
labels:
cozystack.io/ui: "true"
chart:
name: tcp-balancer
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
---
apiVersion: cozystack.io/v1alpha1
kind: CozystackResourceDefinition
metadata:
name: virtualmachine
spec:
application:
kind: VirtualMachine
singular: virtualmachine
plural: virtualmachines
openAPISchema: |
{{- .Files.Get "openapi-schemas/virtual-machine.json" | fromJson | toJson | nindent 6 }}
release:
prefix: virtual-machine-
labels:
cozystack.io/ui: "true"
chart:
name: virtual-machine
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
---
apiVersion: cozystack.io/v1alpha1
kind: CozystackResourceDefinition
metadata:
name: vpn
spec:
application:
kind: VPN
singular: vpn
plural: vpns
openAPISchema: |
{{- .Files.Get "openapi-schemas/vpn.json" | fromJson | toJson | nindent 6 }}
release:
prefix: vpn-
labels:
cozystack.io/ui: "true"
chart:
name: vpn
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
---
apiVersion: cozystack.io/v1alpha1
kind: CozystackResourceDefinition
metadata:
name: mysql
spec:
application:
kind: MySQL
singular: mysql
plural: mysqls
openAPISchema: |
{{- .Files.Get "openapi-schemas/mysql.json" | fromJson | toJson | nindent 6 }}
release:
prefix: mysql-
labels:
cozystack.io/ui: "true"
chart:
name: mysql
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
---
apiVersion: cozystack.io/v1alpha1
kind: CozystackResourceDefinition
metadata:
name: tenant
spec:
application:
kind: Tenant
singular: tenant
plural: tenants
openAPISchema: |
{{- .Files.Get "openapi-schemas/tenant.json" | fromJson | toJson | nindent 6 }}
release:
prefix: tenant-
labels:
cozystack.io/ui: "true"
chart:
name: tenant
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
---
apiVersion: cozystack.io/v1alpha1
kind: CozystackResourceDefinition
metadata:
name: kubernetes
spec:
application:
kind: Kubernetes
singular: kubernetes
plural: kuberneteses
openAPISchema: |
{{- .Files.Get "openapi-schemas/kubernetes.json" | fromJson | toJson | nindent 6 }}
release:
prefix: kubernetes-
labels:
cozystack.io/ui: "true"
chart:
name: kubernetes
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
---
apiVersion: cozystack.io/v1alpha1
kind: CozystackResourceDefinition
metadata:
name: redis
spec:
application:
kind: Redis
singular: redis
plural: redises
openAPISchema: |
{{- .Files.Get "openapi-schemas/redis.json" | fromJson | toJson | nindent 6 }}
release:
prefix: redis-
labels:
cozystack.io/ui: "true"
chart:
name: redis
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
---
apiVersion: cozystack.io/v1alpha1
kind: CozystackResourceDefinition
metadata:
name: rabbitmq
spec:
application:
kind: RabbitMQ
singular: rabbitmq
plural: rabbitmqs
openAPISchema: |
{{- .Files.Get "openapi-schemas/rabbitmq.json" | fromJson | toJson | nindent 6 }}
release:
prefix: rabbitmq-
labels:
cozystack.io/ui: "true"
chart:
name: rabbitmq
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
---
apiVersion: cozystack.io/v1alpha1
kind: CozystackResourceDefinition
metadata:
name: postgres
spec:
application:
kind: Postgres
singular: postgres
plural: postgreses
openAPISchema: |
{{- .Files.Get "openapi-schemas/postgres.json" | fromJson | toJson | nindent 6 }}
release:
prefix: postgres-
labels:
cozystack.io/ui: "true"
chart:
name: postgres
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
---
apiVersion: cozystack.io/v1alpha1
kind: CozystackResourceDefinition
metadata:
name: ferretdb
spec:
application:
kind: FerretDB
singular: ferretdb
plural: ferretdbs
openAPISchema: |
{{- .Files.Get "openapi-schemas/ferretdb.json" | fromJson | toJson | nindent 6 }}
release:
prefix: ferretdb-
labels:
cozystack.io/ui: "true"
chart:
name: ferretdb
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
---
apiVersion: cozystack.io/v1alpha1
kind: CozystackResourceDefinition
metadata:
name: kafka
spec:
application:
kind: Kafka
singular: kafka
plural: kafkas
openAPISchema: |
{{- .Files.Get "openapi-schemas/kafka.json" | fromJson | toJson | nindent 6 }}
release:
prefix: kafka-
labels:
cozystack.io/ui: "true"
chart:
name: kafka
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
---
apiVersion: cozystack.io/v1alpha1
kind: CozystackResourceDefinition
metadata:
name: vmdisk
spec:
application:
kind: VMDisk
singular: vmdisk
plural: vmdisks
openAPISchema: |
{{- .Files.Get "openapi-schemas/vm-disk.json" | fromJson | toJson | nindent 6 }}
release:
prefix: vm-disk-
labels:
cozystack.io/ui: "true"
chart:
name: vm-disk
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
---
apiVersion: cozystack.io/v1alpha1
kind: CozystackResourceDefinition
metadata:
name: vminstance
spec:
application:
kind: VMInstance
singular: vminstance
plural: vminstances
openAPISchema: |
{{- .Files.Get "openapi-schemas/vm-instance.json" | fromJson | toJson | nindent 6 }}
release:
prefix: vm-instance-
labels:
cozystack.io/ui: "true"
chart:
name: vm-instance
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
---
apiVersion: cozystack.io/v1alpha1
kind: CozystackResourceDefinition
metadata:
name: monitoring
spec:
application:
kind: Monitoring
singular: monitoring
plural: monitorings
openAPISchema: |
{{- .Files.Get "openapi-schemas/monitoring.json" | fromJson | toJson | nindent 6 }}
release:
prefix: ""
labels:
cozystack.io/ui: "true"
chart:
name: monitoring
sourceRef:
kind: HelmRepository
name: cozystack-extra
namespace: cozy-public
---
apiVersion: cozystack.io/v1alpha1
kind: CozystackResourceDefinition
metadata:
name: etcd
spec:
application:
kind: Etcd
singular: etcd
plural: etcds
openAPISchema: |
{{- .Files.Get "openapi-schemas/etcd.json" | fromJson | toJson | nindent 6 }}
release:
prefix: ""
labels:
cozystack.io/ui: "true"
chart:
name: etcd
sourceRef:
kind: HelmRepository
name: cozystack-extra
namespace: cozy-public
---
apiVersion: cozystack.io/v1alpha1
kind: CozystackResourceDefinition
metadata:
name: ingress
spec:
application:
kind: Ingress
singular: ingress
plural: ingresses
openAPISchema: |
{{- .Files.Get "openapi-schemas/ingress.json" | fromJson | toJson | nindent 6 }}
release:
prefix: ""
labels:
cozystack.io/ui: "true"
chart:
name: ingress
sourceRef:
kind: HelmRepository
name: cozystack-extra
namespace: cozy-public
---
apiVersion: cozystack.io/v1alpha1
kind: CozystackResourceDefinition
metadata:
name: seaweedfs
spec:
application:
kind: SeaweedFS
singular: seaweedfs
plural: seaweedfses
openAPISchema: |
{{- .Files.Get "openapi-schemas/seaweedfs.json" | fromJson | toJson | nindent 6 }}
release:
prefix: ""
labels:
cozystack.io/ui: "true"
chart:
name: seaweedfs
sourceRef:
kind: HelmRepository
name: cozystack-extra
namespace: cozy-public
---
apiVersion: cozystack.io/v1alpha1
kind: CozystackResourceDefinition
metadata:
name: bootbox
spec:
application:
kind: BootBox
singular: bootbox
plural: bootboxes
openAPISchema: |
{{- .Files.Get "openapi-schemas/bootbox.json" | fromJson | toJson | nindent 6 }}
release:
prefix: ""
labels:
cozystack.io/ui: "true"
chart:
name: bootbox
sourceRef:
kind: HelmRepository
name: cozystack-extra
namespace: cozy-public
---
apiVersion: cozystack.io/v1alpha1
kind: CozystackResourceDefinition
metadata:
name: info
spec:
application:
kind: Info
singular: info
plural: infos
openAPISchema: |
{{- .Files.Get "openapi-schemas/info.json" | fromJson | toJson | nindent 6 }}
release:
prefix: ""
labels:
cozystack.io/ui: "true"
chart:
name: info
sourceRef:
kind: HelmRepository
name: cozystack-extra
namespace: cozy-public

View File

@@ -14,22 +14,8 @@ spec:
metadata:
labels:
app: cozystack-api
annotations:
checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
spec:
serviceAccountName: cozystack-api
containers:
- name: cozystack-api
image: "{{ .Values.cozystackAPI.image }}"
args: ["--config=/config/config.yaml"]
volumeMounts:
- name: config-volume
mountPath: /config/config.yaml
subPath: config.yaml
volumes:
- name: config-volume
configMap:
name: cozystack-api
items:
- key: config.yaml
path: config.yaml

View File

@@ -4,14 +4,17 @@ metadata:
name: cozystack-api
rules:
- apiGroups: [""]
resources: ["namespaces"]
resources: ["namespaces", "secrets"]
verbs: ["get", "watch", "list"]
- apiGroups: ["admissionregistration.k8s.io"]
resources: ["mutatingwebhookconfigurations", "validatingwebhookconfigurations", "validatingadmissionpolicies", "validatingadmissionpolicybindings"]
verbs: ["get", "watch", "list"]
- apiGroups: ["flowcontrol.apiserver.k8s.io"]
resources: ['prioritylevelconfigurations', 'flowschemas']
verbs: ['list', 'watch']
- apiGroups: ['helm.toolkit.fluxcd.io']
resources: ['*']
verbs: ['*']
resources: ["prioritylevelconfigurations", "flowschemas"]
verbs: ["list", "watch"]
- apiGroups: ["cozystack.io"]
resources: ["*"]
verbs: ["get", "watch", "list"]
- apiGroups: ["helm.toolkit.fluxcd.io"]
resources: ["*"]
verbs: ["*"]

View File

@@ -0,0 +1,26 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: tenantnamespaces-read
rules:
- apiGroups:
- core.cozystack.io
resources:
- tenantnamespaces
verbs:
- get
- list
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: tenantnamespaces-read-authenticated
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: tenantnamespaces-read
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: system:authenticated

View File

@@ -1,2 +1,2 @@
cozystackAPI:
image: ghcr.io/cozystack/cozystack/cozystack-api:v0.35.0-alpha.1@sha256:677b5af99f2b7d1adb4c25d5637f2fa5a1baffb423269fa166d2ea15a0028864
image: ghcr.io/cozystack/cozystack/cozystack-api:v0.35.0-alpha.3@sha256:d4cfc2afacc30d383f7b5454e97bb77f2e9bfc33dbc3dc512bfe671300e3ad51

View File

@@ -0,0 +1,115 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.16.4
name: cozystackresourcedefinitions.cozystack.io
spec:
group: cozystack.io
names:
kind: CozystackResourceDefinition
listKind: CozystackResourceDefinitionList
plural: cozystackresourcedefinitions
singular: cozystackresourcedefinition
scope: Namespaced
versions:
- name: v1alpha1
schema:
openAPIV3Schema:
description: CozystackResourceDefinition is the Schema for the cozystackresourcedefinitions
API
properties:
apiVersion:
description: |-
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
type: string
kind:
description: |-
Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
type: string
metadata:
type: object
spec:
properties:
application:
description: Application configuration
properties:
kind:
description: Kind of the application, used for UI and API
type: string
openAPISchema:
description: OpenAPI schema for the application, used for API
validation
type: string
plural:
description: Plural name of the application, used for UI and API
type: string
singular:
description: Singular name of the application, used for UI and
API
type: string
required:
- kind
- openAPISchema
- plural
- singular
type: object
release:
description: Release configuration
properties:
chart:
description: Helm chart configuration
properties:
name:
description: Name of the Helm chart
type: string
sourceRef:
description: Source reference for the Helm chart
properties:
kind:
default: HelmRepository
description: Kind of the source reference
type: string
name:
description: Name of the source reference
type: string
namespace:
default: cozy-public
description: Namespace of the source reference
type: string
required:
- kind
- name
- namespace
type: object
required:
- name
- sourceRef
type: object
labels:
additionalProperties:
type: string
description: Labels for the release
type: object
prefix:
description: Prefix for the release name
type: string
required:
- chart
- prefix
type: object
required:
- application
- release
type: object
type: object
served: true
storage: true

View File

@@ -1,5 +1,5 @@
cozystackController:
image: ghcr.io/cozystack/cozystack/cozystack-controller:v0.35.0-alpha.1@sha256:7a510d046d7e1dd1f82a06f7a014bf7690f95cbd42005a417520b216141f86a0
image: ghcr.io/cozystack/cozystack/cozystack-controller:v0.35.0-alpha.3@sha256:98d0b945630c3dd7c39adc7a5326f0e0e0b49a18641bec911aeb6c62beca4e1f
debug: false
disableTelemetry: false
cozystackVersion: "v0.35.0-alpha.1"
cozystackVersion: "v0.35.0-alpha.3"

View File

@@ -76,7 +76,7 @@ data:
"kubeappsNamespace": {{ .Release.Namespace | quote }},
"helmGlobalNamespace": {{ include "kubeapps.helmGlobalPackagingNamespace" . | quote }},
"carvelGlobalNamespace": {{ .Values.kubeappsapis.pluginConfig.kappController.packages.v1alpha1.globalPackagingNamespace | quote }},
"appVersion": "v0.35.0-alpha.1",
"appVersion": "v0.35.0-alpha.3",
"authProxyEnabled": {{ .Values.authProxy.enabled }},
"oauthLoginURI": {{ .Values.authProxy.oauthLoginURI | quote }},
"oauthLogoutURI": {{ .Values.authProxy.oauthLogoutURI | quote }},

View File

@@ -1,7 +1,7 @@
FROM bitnami/node:20.15.1 AS build
WORKDIR /app
ARG COMMIT_REF=cdf9095f50c74505870de337725d2a9d0bd20947
ARG COMMIT_REF=4926bc68fabb0914afab574006643c85a597b371
RUN wget -O- https://github.com/cozystack/kubeapps/archive/${COMMIT_REF}.tar.gz | tar xzf - --strip-components=2 kubeapps-${COMMIT_REF}/dashboard
RUN yarn install --frozen-lockfile

View File

@@ -4,7 +4,7 @@
# syntax = docker/dockerfile:1
FROM alpine AS source
ARG COMMIT_REF=cdf9095f50c74505870de337725d2a9d0bd20947
ARG COMMIT_REF=4926bc68fabb0914afab574006643c85a597b371
RUN apk add --no-cache patch
WORKDIR /source
RUN wget -O- https://github.com/cozystack/kubeapps/archive/${COMMIT_REF}.tar.gz | tar xzf - --strip-components=1

View File

@@ -19,7 +19,7 @@ kubeapps:
image:
registry: ghcr.io/cozystack/cozystack
repository: dashboard
tag: v0.35.0-alpha.1
tag: v0.35.0-alpha.3
digest: "sha256:ad4b95660b6c5c1b9736ca4768a3f9648705c2855d0a08880d570b4e480dba78"
redis:
master:
@@ -37,8 +37,8 @@ kubeapps:
image:
registry: ghcr.io/cozystack/cozystack
repository: kubeapps-apis
tag: v0.35.0-alpha.1
digest: "sha256:5eb100bab12012659caaa335e510438fec4db22929d2ff8131d51572f609c4b5"
tag: v0.35.0-alpha.3
digest: "sha256:55b1aacdcb8f7e96b75396e461fbba612498095515b9a437b8f925802f06c485"
pluginConfig:
flux:
packages:

View File

@@ -3,7 +3,7 @@ kamaji:
deploy: false
image:
pullPolicy: IfNotPresent
tag: v0.35.0-alpha.1@sha256:7ce47da363e7be4f297e6de42a72416238c66c613e2effdbfa3fef987701d61a
tag: v0.35.0-alpha.3@sha256:34500654751ceef7a57562fb1edc6928d91245ad8e41da732788dcf10ec330b5
repository: ghcr.io/cozystack/cozystack/kamaji
resources:
limits:

View File

@@ -200,7 +200,7 @@ spec:
- groups
- kubernetes-client
redirectUris:
- "http://dashboard.{{ $host }}/oauth2/callback/*"
- "https://dashboard.{{ $host }}/oauth2/callback/*"
{{- range $i, $v := $extraRedirectUris }}
- "{{ $v }}"
{{- end }}
@@ -223,8 +223,7 @@ data:
clientSecret: {{ $kubeappsClient }}
cookieSecret: {{ $cookieSecret }}
extraFlags:
- --ssl-insecure-skip-verify
- --cookie-secure=false
- --cookie-secure
- --scope=openid email groups
- --oidc-issuer-url=https://keycloak.{{ $host }}/realms/cozy

View File

@@ -87,7 +87,10 @@ spec:
- name: KEYCLOAK_ADMIN
value: admin
- name: KEYCLOAK_ADMIN_PASSWORD
value: {{ $password }}
valueFrom:
secretKeyRef:
name: {{ .Release.Name }}-credentials
key: password
- name: KC_DB
value: "postgres"
- name: KC_DB_URL_HOST

View File

@@ -1,3 +1,3 @@
portSecurity: true
routes: ""
image: ghcr.io/cozystack/cozystack/kubeovn-webhook:v0.35.0-alpha.1@sha256:dab57f5f68e77830b63c37c1b0c3228f404137435eced38bb21982954e280398
image: ghcr.io/cozystack/cozystack/kubeovn-webhook:v0.35.0-alpha.3@sha256:ad4e506065458b039a86c7f03a35dbb6918756e117ce74dd931089383cfd91f8

View File

@@ -64,4 +64,4 @@ global:
images:
kubeovn:
repository: kubeovn
tag: v1.13.14@sha256:beb6e0bac9321fe9b26a11b24bf99a7e176af5e60a2826acc34a7edec5198e6a
tag: v1.13.14@sha256:bacd68243ee9fd94f5f0e377801ed3e99cd0762ff5df0d0ec73a73130180d8ca

View File

@@ -1,3 +1,3 @@
storageClass: replicated
csiDriver:
image: ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.26.0@sha256:445c2727b04ac68595b43c988ff17b3d69a7b22b0644fde3b10c65b47a7bc036
image: ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.26.2@sha256:761e7235ff9cb7f6f223f00954943e6a5af32ed6624ee592a8610122f96febb0

View File

@@ -1,3 +1,3 @@
objectstorage:
controller:
image: "ghcr.io/cozystack/cozystack/objectstorage-controller:v0.35.0-alpha.1@sha256:2fe77880b81b0210273c85a142cb13e6857d13dd941337456b426597f5778bc3"
image: "ghcr.io/cozystack/cozystack/objectstorage-controller:v0.35.0-alpha.3@sha256:4d3f20ae946736d9260193dd1ce0e72114ad6bd6f78fb6528a68efffa2092b07"

View File

@@ -8,4 +8,5 @@ update:
curl -sSL https://github.com/seaweedfs/seaweedfs/archive/refs/heads/master.tar.gz | \
tar xzvf - --strip 3 -C charts seaweedfs-master/k8s/charts/seaweedfs
patch --no-backup-if-mismatch -p4 < patches/resize-api-server-annotation.diff
patch --no-backup-if-mismatch -p4 < patches/fix-volume-servicemonitor.patch
#patch --no-backup-if-mismatch -p4 < patches/retention-policy-delete.yaml

View File

@@ -21,9 +21,9 @@ metadata:
{{- with $.Values.global.monitoring.additionalLabels }}
{{- toYaml . | nindent 4 }}
{{- end }}
{{- if .Values.volume.annotations }}
{{- if $.Values.volume.annotations }}
annotations:
{{- toYaml .Values.volume.annotations | nindent 4 }}
{{- toYaml $.Values.volume.annotations | nindent 4 }}
{{- end }}
spec:
endpoints:

View File

@@ -0,0 +1,15 @@
diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/volume-servicemonitor.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/volume-servicemonitor.yaml
--- a/packages/system/seaweedfs/charts/seaweedfs/templates/volume-servicemonitor.yaml (revision 8951bc13d7d02b5e6982a239570ed58ed7cb025a)
+++ b/packages/system/seaweedfs/charts/seaweedfs/templates/volume-servicemonitor.yaml (revision fa4fff2292c4b79a92db5cd654a3c6bf590252a6)
@@ -21,9 +21,9 @@
{{- with $.Values.global.monitoring.additionalLabels }}
{{- toYaml . | nindent 4 }}
{{- end }}
-{{- if .Values.volume.annotations }}
+{{- if $.Values.volume.annotations }}
annotations:
- {{- toYaml .Values.volume.annotations | nindent 4 }}
+ {{- toYaml $.Values.volume.annotations | nindent 4 }}
{{- end }}
spec:
endpoints:

View File

@@ -4,6 +4,8 @@ global:
extraEnvironmentVars:
WEED_CLUSTER_SW_MASTER: "seaweedfs-master:9333"
WEED_CLUSTER_SW_FILER: "seaweedfs-filer-client:8888"
monitoring:
enabled: true
seaweedfs:
master:
replicas: 3
@@ -78,7 +80,10 @@ seaweedfs:
existingConfigSecret: null
auditLogConfig: {}
s3:
enabled: true
enableAuth: true
readinessProbe:
scheme: HTTPS
logs:
type: ""
ingress:
@@ -94,6 +99,13 @@ seaweedfs:
- hosts:
- seaweedfs.demo.cozystack.io
secretName: seaweedfs-s3-ingress-tls
resources:
limits:
cpu: "2"
memory: "2Gi"
requests:
cpu: "500m"
memory: "1Gi"
cosi:
enabled: true
podLabels:
@@ -102,7 +114,7 @@ seaweedfs:
bucketClassName: "seaweedfs"
region: ""
sidecar:
image: "ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.35.0-alpha.1@sha256:e4f9a7302285ea9febeb28fc2fa97cb7c01bb91e602f975c31aad1fe46f778f7"
image: "ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.35.0-alpha.3@sha256:4a67ec40c13bf912151957dc0e7409f7e01a2859905285c98c20baae7b667ae2"
certificates:
commonName: "SeaweedFS CA"
ipAddresses: []

View File

@@ -1,3 +1,3 @@
apiVersion: v2
name: cozy-volumesnapshot-crd-for-tenant-k8s
name: cozy-vsnap-crd
version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process

View File

@@ -1,4 +1,4 @@
export NAME=volumesnapshot-crd-for-tenant-k8s
export NAME=vsnap-crd
export NAMESPACE=cozy-$(NAME)
include ../../../scripts/package.mk

View File

@@ -1,18 +1,5 @@
/*
Copyright 2024 The Cozystack Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// SPDX-License-Identifier: Apache-2.0
// Copyright 2025 The Cozystack Authors.
package v1alpha1
@@ -24,46 +11,50 @@ import (
"k8s.io/klog/v2"
)
// GroupName holds the API group name.
// -----------------------------------------------------------------------------
// Group / version boiler-plate
// -----------------------------------------------------------------------------
// GroupName is the API group for every resource in this package.
const GroupName = "apps.cozystack.io"
var (
RegisteredGVKs []schema.GroupVersionKind
)
// SchemeGroupVersion is group version used to register these objects
// SchemeGroupVersion is the canonical {group,version} for v1alpha1.
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha1"}
// -----------------------------------------------------------------------------
// Scheme registration helpers
// -----------------------------------------------------------------------------
var (
// SchemeBuilder allows to add this group to a scheme.
// TODO: move SchemeBuilder with zz_generated.deepcopy.go to k8s.io/api.
// localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes.
// SchemeBuilder is used by generated deepcopy code.
SchemeBuilder runtime.SchemeBuilder
localSchemeBuilder = &SchemeBuilder
// AddToScheme adds this group to a scheme.
AddToScheme = localSchemeBuilder.AddToScheme
AddToScheme = localSchemeBuilder.AddToScheme
)
func init() {
// We only register manually written functions here. The registration of the
// generated functions takes place in the generated files. The separation
// makes the code compile even when the generated files are missing.
// Manually-written types go here. Generated deepcopy code is wired in
// via `zz_generated.deepcopy.go`.
localSchemeBuilder.Register(addKnownTypes)
}
// Adds the list of known types to the given scheme.
// addKnownTypes is called from init().
func addKnownTypes(scheme *runtime.Scheme) error {
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
return nil
}
// Resource takes an unqualified resource and returns a Group qualified GroupResource
// Resource turns an unqualified resource name into a fully-qualified one.
func Resource(resource string) schema.GroupResource {
return SchemeGroupVersion.WithResource(resource).GroupResource()
}
// RegisterDynamicTypes registers types dynamically based on config
// -----------------------------------------------------------------------------
// Public helpers consumed by the apiserver wiring
// -----------------------------------------------------------------------------
// RegisterDynamicTypes adds per-tenant “Application” kinds that are only known
// at runtime from a config file.
func RegisterDynamicTypes(scheme *runtime.Scheme, cfg *config.ResourceConfig) error {
for _, res := range cfg.Resources {
kind := res.Application.Kind
@@ -76,9 +67,7 @@ func RegisterDynamicTypes(scheme *runtime.Scheme, cfg *config.ResourceConfig) er
scheme.AddKnownTypeWithName(gvkInternal, &Application{})
scheme.AddKnownTypeWithName(gvkInternal.GroupVersion().WithKind(kind+"List"), &ApplicationList{})
klog.V(1).Infof("Registered kind: %s\n", kind)
RegisteredGVKs = append(RegisteredGVKs, gvk)
klog.V(1).Infof("Registered dynamic kind: %s", kind)
}
return nil
}

View File

@@ -0,0 +1,33 @@
/*
Copyright 2024 The Cozystack Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package fuzzer
import (
"github.com/cozystack/cozystack/pkg/apis/core"
fuzz "github.com/google/gofuzz"
runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer"
)
// Funcs returns the fuzzer functions for the core api group.
var Funcs = func(codecs runtimeserializer.CodecFactory) []interface{} {
return []interface{}{
func(s *core.TenantNamespaceSpec, c fuzz.Continue) {
c.FuzzNoCustom(s) // fuzz self without calling this function again
},
}
}

View File

@@ -0,0 +1,29 @@
/*
Copyright 2024 The Cozystack Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package install
import (
corev1alpha1 "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1"
"k8s.io/apimachinery/pkg/runtime"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
)
// Install registers the API group and adds types to a scheme
func Install(scheme *runtime.Scheme) {
utilruntime.Must(corev1alpha1.AddToScheme(scheme))
utilruntime.Must(scheme.SetVersionPriority(corev1alpha1.SchemeGroupVersion))
}

View File

@@ -0,0 +1,30 @@
/*
Copyright 2024 The Cozystack Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package install
import (
"testing"
corefuzzer "github.com/cozystack/cozystack/pkg/apis/core/fuzzer"
"k8s.io/apimachinery/pkg/api/apitesting/roundtrip"
)
func TestRoundTripTypes(t *testing.T) {
roundtrip.RoundTripTestForAPIGroup(t, Install, corefuzzer.Funcs)
// TODO: enable protobuf generation for the sample-apiserver
// roundtrip.RoundTripProtobufTestForAPIGroup(t, Install, corefuzzer.Funcs)
}

22
pkg/apis/core/register.go Normal file
View File

@@ -0,0 +1,22 @@
/*
Copyright 2024 The Cozystack Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package core
// GroupName is the group name used in this package
const (
GroupName = "core.cozystack.io"
)

View File

@@ -0,0 +1,25 @@
/*
Copyright 2024 The Cozystack Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// +k8s:openapi-gen=true
// +k8s:deepcopy-gen=package
// +k8s:conversion-gen=github.com/cozystack/cozystack/pkg/apis/core
// +k8s:conversion-gen=k8s.io/apiextensions-apiserver/pkg/apis/apiextensions
// +k8s:defaulter-gen=TypeMeta
// +groupName=core.cozystack.io
// Package v1alpha1 is the v1alpha1 version of the API.
package v1alpha1 // import "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1"

View File

@@ -0,0 +1,65 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2025 The Cozystack Authors.
package v1alpha1
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/klog/v2"
)
// -----------------------------------------------------------------------------
// Group / version boiler-plate
// -----------------------------------------------------------------------------
// GroupName is the API group for every resource in this package.
const GroupName = "core.cozystack.io"
// SchemeGroupVersion is the canonical {group,version} for v1alpha1.
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha1"}
// -----------------------------------------------------------------------------
// Scheme registration helpers
// -----------------------------------------------------------------------------
var (
// SchemeBuilder is used by generated deepcopy code.
SchemeBuilder runtime.SchemeBuilder
localSchemeBuilder = &SchemeBuilder
AddToScheme = localSchemeBuilder.AddToScheme
)
func init() {
// Manually-written types go here. Generated deepcopy code is wired in
// via `zz_generated.deepcopy.go`.
localSchemeBuilder.Register(addKnownTypes)
}
// addKnownTypes is called from init().
func addKnownTypes(scheme *runtime.Scheme) error {
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
return nil
}
// Resource turns an unqualified resource name into a fully-qualified one.
func Resource(resource string) schema.GroupResource {
return SchemeGroupVersion.WithResource(resource).GroupResource()
}
// -----------------------------------------------------------------------------
// Public helpers consumed by the apiserver wiring
// -----------------------------------------------------------------------------
// RegisterStaticTypes adds *compile-time* resources such as TenantNamespace.
func RegisterStaticTypes(scheme *runtime.Scheme) {
scheme.AddKnownTypes(SchemeGroupVersion,
&TenantNamespace{},
&TenantNamespaceList{},
&TenantSecret{},
&TenantSecretList{},
)
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
klog.V(1).Info("Registered static kinds: TenantNamespace, TenantSecret")
}

View File

@@ -0,0 +1,30 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2025 The Cozystack Authors.
// This file contains the cluster-scoped “TenantNamespace” resource.
// A TenantNamespace represents an existing Kubernetes Namespace whose
// *name* starts with the prefix “tenant-”.
package v1alpha1
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// TenantNamespace is a thin wrapper around ObjectMeta. It has no spec/status
// because it merely reflects an existing Namespace object.
type TenantNamespace struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// TenantNamespaceList is the list variant for TenantNamespace.
type TenantNamespaceList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []TenantNamespace `json:"items"`
}

View File

@@ -0,0 +1,24 @@
// SPDX-License-Identifier: Apache-2.0
package v1alpha1
import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type TenantSecret struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
// Same semantics as core/v1 Secret.
Type string `json:"type,omitempty"`
Data map[string][]byte `json:"data,omitempty"`
StringData map[string]string `json:"stringData,omitempty"` // write-only hint
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type TenantSecretList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []TenantSecret `json:"items"`
}

View File

@@ -0,0 +1,36 @@
//go:build !ignore_autogenerated
// +build !ignore_autogenerated
/*
Copyright 2025 The Cozystack Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by conversion-gen. DO NOT EDIT.
package v1alpha1
import (
runtime "k8s.io/apimachinery/pkg/runtime"
)
func init() {
localSchemeBuilder.Register(RegisterConversions)
}
// RegisterConversions adds conversion functions to the given scheme.
// Public to allow building arbitrary schemes.
func RegisterConversions(s *runtime.Scheme) error {
return nil
}

View File

@@ -0,0 +1,166 @@
//go:build !ignore_autogenerated
// +build !ignore_autogenerated
/*
Copyright 2025 The Cozystack Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by deepcopy-gen. DO NOT EDIT.
package v1alpha1
import (
runtime "k8s.io/apimachinery/pkg/runtime"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TenantNamespace) DeepCopyInto(out *TenantNamespace) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TenantNamespace.
func (in *TenantNamespace) DeepCopy() *TenantNamespace {
if in == nil {
return nil
}
out := new(TenantNamespace)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *TenantNamespace) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TenantNamespaceList) DeepCopyInto(out *TenantNamespaceList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]TenantNamespace, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TenantNamespaceList.
func (in *TenantNamespaceList) DeepCopy() *TenantNamespaceList {
if in == nil {
return nil
}
out := new(TenantNamespaceList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *TenantNamespaceList) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TenantSecret) DeepCopyInto(out *TenantSecret) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
if in.Data != nil {
in, out := &in.Data, &out.Data
*out = make(map[string][]byte, len(*in))
for key, val := range *in {
var outVal []byte
if val == nil {
(*out)[key] = nil
} else {
in, out := &val, &outVal
*out = make([]byte, len(*in))
copy(*out, *in)
}
(*out)[key] = outVal
}
}
if in.StringData != nil {
in, out := &in.StringData, &out.StringData
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TenantSecret.
func (in *TenantSecret) DeepCopy() *TenantSecret {
if in == nil {
return nil
}
out := new(TenantSecret)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *TenantSecret) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TenantSecretList) DeepCopyInto(out *TenantSecretList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]TenantSecret, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TenantSecretList.
func (in *TenantSecretList) DeepCopy() *TenantSecretList {
if in == nil {
return nil
}
out := new(TenantSecretList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *TenantSecretList) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}

View File

@@ -0,0 +1,33 @@
//go:build !ignore_autogenerated
// +build !ignore_autogenerated
/*
Copyright 2025 The Cozystack Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by defaulter-gen. DO NOT EDIT.
package v1alpha1
import (
runtime "k8s.io/apimachinery/pkg/runtime"
)
// RegisterDefaults adds defaulters functions to the given scheme.
// Public to allow building arbitrary schemes.
// All generated defaulters are covering - they call all nested defaulters.
func RegisterDefaults(scheme *runtime.Scheme) error {
return nil
}

View File

@@ -0,0 +1,40 @@
/*
Copyright 2024 The Cozystack Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package validation
import (
"github.com/cozystack/cozystack/pkg/apis/core"
"k8s.io/apimachinery/pkg/util/validation/field"
)
// ValidateTenantNamespace validates a TenantNamespace.
func ValidateTenantNamespace(f *core.TenantNamespace) field.ErrorList {
allErrs := field.ErrorList{}
allErrs = append(allErrs, ValidateTenantNamespaceSpec(&f.Spec, field.NewPath("spec"))...)
return allErrs
}
// ValidateTenantNamespaceSpec validates a TenantNamespaceSpec.
func ValidateTenantNamespaceSpec(s *core.TenantNamespaceSpec, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
// TODO validation
return allErrs
}

View File

@@ -27,13 +27,18 @@ import (
"k8s.io/apiserver/pkg/registry/rest"
genericapiserver "k8s.io/apiserver/pkg/server"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/kubernetes"
restclient "k8s.io/client-go/rest"
"github.com/cozystack/cozystack/pkg/apis/apps"
"github.com/cozystack/cozystack/pkg/apis/apps/install"
appsinstall "github.com/cozystack/cozystack/pkg/apis/apps/install"
coreinstall "github.com/cozystack/cozystack/pkg/apis/apps/install"
"github.com/cozystack/cozystack/pkg/apis/core"
"github.com/cozystack/cozystack/pkg/config"
appsregistry "github.com/cozystack/cozystack/pkg/registry"
cozyregistry "github.com/cozystack/cozystack/pkg/registry"
applicationstorage "github.com/cozystack/cozystack/pkg/registry/apps/application"
tenantnamespacestorage "github.com/cozystack/cozystack/pkg/registry/core/tenantnamespace"
tenantsecretstorage "github.com/cozystack/cozystack/pkg/registry/core/tenantsecret"
)
var (
@@ -42,11 +47,12 @@ var (
// Codecs provides methods for retrieving codecs and serializers for specific
// versions and content types.
Codecs = serializer.NewCodecFactory(Scheme)
AppsComponentName = "apps"
CozyComponentName = "cozy"
)
func init() {
install.Install(Scheme)
appsinstall.Install(Scheme)
coreinstall.Install(Scheme)
// Register HelmRelease types.
if err := helmv2.AddToScheme(Scheme); err != nil {
@@ -73,8 +79,8 @@ type Config struct {
ResourceConfig *config.ResourceConfig
}
// AppsServer holds the state for the Kubernetes master/api server.
type AppsServer struct {
// CozyServer holds the state for the Kubernetes master/api server.
type CozyServer struct {
GenericAPIServer *genericapiserver.GenericAPIServer
}
@@ -98,19 +104,17 @@ func (cfg *Config) Complete() CompletedConfig {
return CompletedConfig{&c}
}
// New returns a new instance of AppsServer from the given configuration.
func (c completedConfig) New() (*AppsServer, error) {
genericServer, err := c.GenericConfig.New("apps-apiserver", genericapiserver.NewEmptyDelegate())
// New returns a new instance of CozyServer from the given configuration.
func (c completedConfig) New() (*CozyServer, error) {
genericServer, err := c.GenericConfig.New("cozy-apiserver", genericapiserver.NewEmptyDelegate())
if err != nil {
return nil, err
}
s := &AppsServer{
s := &CozyServer{
GenericAPIServer: genericServer,
}
apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(apps.GroupName, Scheme, metav1.ParameterCodec, Codecs)
// Create a dynamic client for HelmRelease using InClusterConfig.
inClusterConfig, err := restclient.InClusterConfig()
if err != nil {
@@ -122,16 +126,41 @@ func (c completedConfig) New() (*AppsServer, error) {
return nil, fmt.Errorf("unable to create dynamic client: %v", err)
}
v1alpha1storage := map[string]rest.Storage{}
for _, resConfig := range c.ResourceConfig.Resources {
storage := applicationstorage.NewREST(dynamicClient, &resConfig)
v1alpha1storage[resConfig.Application.Plural] = appsregistry.RESTInPeace(storage)
clientset, err := kubernetes.NewForConfig(inClusterConfig)
if err != nil {
return nil, fmt.Errorf("create kube clientset: %v", err)
}
apiGroupInfo.VersionedResourcesStorageMap["v1alpha1"] = v1alpha1storage
// --- static, cluster-scoped resource for core group ---
coreV1alpha1Storage := map[string]rest.Storage{}
coreV1alpha1Storage["tenantnamespaces"] = cozyregistry.RESTInPeace(
tenantnamespacestorage.NewREST(
clientset.CoreV1(),
clientset.AuthorizationV1(),
20,
),
)
coreV1alpha1Storage["tenantsecrets"] = cozyregistry.RESTInPeace(
tenantsecretstorage.NewREST(
clientset.CoreV1(),
),
)
if err := s.GenericAPIServer.InstallAPIGroup(&apiGroupInfo); err != nil {
coreApiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(core.GroupName, Scheme, metav1.ParameterCodec, Codecs)
coreApiGroupInfo.VersionedResourcesStorageMap["v1alpha1"] = coreV1alpha1Storage
if err := s.GenericAPIServer.InstallAPIGroup(&coreApiGroupInfo); err != nil {
return nil, err
}
// --- dynamically-configured, per-tenant resources ---
appsV1alpha1Storage := map[string]rest.Storage{}
for _, resConfig := range c.ResourceConfig.Resources {
storage := applicationstorage.NewREST(dynamicClient, &resConfig)
appsV1alpha1Storage[resConfig.Application.Plural] = cozyregistry.RESTInPeace(storage)
}
appsApiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(apps.GroupName, Scheme, metav1.ParameterCodec, Codecs)
appsApiGroupInfo.VersionedResourcesStorageMap["v1alpha1"] = appsV1alpha1Storage
if err := s.GenericAPIServer.InstallAPIGroup(&appsApiGroupInfo); err != nil {
return nil, err
}

View File

@@ -20,9 +20,11 @@ import (
"testing"
appsfuzzer "github.com/cozystack/cozystack/pkg/apis/apps/fuzzer"
corefuzzer "github.com/cozystack/cozystack/pkg/apis/core/fuzzer"
"k8s.io/apimachinery/pkg/api/apitesting/roundtrip"
)
func TestRoundTripTypes(t *testing.T) {
roundtrip.RoundTripTestForScheme(t, Scheme, appsfuzzer.Funcs)
roundtrip.RoundTripTestForScheme(t, Scheme, corefuzzer.Funcs)
}

View File

@@ -25,11 +25,14 @@ import (
"io"
"net"
"github.com/cozystack/cozystack/pkg/apis/apps/v1alpha1"
v1alpha1 "github.com/cozystack/cozystack/api/v1alpha1"
appsv1alpha1 "github.com/cozystack/cozystack/pkg/apis/apps/v1alpha1"
corev1alpha1 "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1"
"github.com/cozystack/cozystack/pkg/apiserver"
"github.com/cozystack/cozystack/pkg/config"
sampleopenapi "github.com/cozystack/cozystack/pkg/generated/openapi"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/runtime"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/util/version"
@@ -38,35 +41,37 @@ import (
genericoptions "k8s.io/apiserver/pkg/server/options"
utilfeature "k8s.io/apiserver/pkg/util/feature"
utilversionpkg "k8s.io/apiserver/pkg/util/version"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/component-base/featuregate"
baseversion "k8s.io/component-base/version"
netutils "k8s.io/utils/net"
"sigs.k8s.io/controller-runtime/pkg/client"
)
// AppsServerOptions holds the state for the Apps API server
type AppsServerOptions struct {
// CozyServerOptions holds the state for the Cozy API server
type CozyServerOptions struct {
RecommendedOptions *genericoptions.RecommendedOptions
StdOut io.Writer
StdErr io.Writer
AlternateDNS []string
// Add a field to store the configuration path
ResourceConfigPath string
Client client.Client
// Add a field to store the configuration
ResourceConfig *config.ResourceConfig
}
// NewAppsServerOptions returns a new instance of AppsServerOptions
func NewAppsServerOptions(out, errOut io.Writer) *AppsServerOptions {
o := &AppsServerOptions{
// NewCozyServerOptions returns a new instance of CozyServerOptions
func NewCozyServerOptions(out, errOut io.Writer) *CozyServerOptions {
o := &CozyServerOptions{
RecommendedOptions: genericoptions.NewRecommendedOptions(
"",
apiserver.Codecs.LegacyCodec(v1alpha1.SchemeGroupVersion),
apiserver.Codecs.LegacyCodec(
corev1alpha1.SchemeGroupVersion,
appsv1alpha1.SchemeGroupVersion,
),
),
StdOut: out,
StdErr: errOut,
}
@@ -74,12 +79,12 @@ func NewAppsServerOptions(out, errOut io.Writer) *AppsServerOptions {
return o
}
// NewCommandStartAppsServer provides a CLI handler for the 'start apps-server' command
func NewCommandStartAppsServer(ctx context.Context, defaults *AppsServerOptions) *cobra.Command {
// NewCommandStartCozyServer provides a CLI handler for the 'start apps-server' command
func NewCommandStartCozyServer(ctx context.Context, defaults *CozyServerOptions) *cobra.Command {
o := *defaults
cmd := &cobra.Command{
Short: "Launch an Apps API server",
Long: "Launch an Apps API server",
Short: "Launch an Cozystack API server",
Long: "Launch an Cozystack API server",
PersistentPreRunE: func(*cobra.Command, []string) error {
return utilversionpkg.DefaultComponentGlobalsRegistry.Set()
},
@@ -90,7 +95,7 @@ func NewCommandStartAppsServer(ctx context.Context, defaults *AppsServerOptions)
if err := o.Validate(args); err != nil {
return err
}
if err := o.RunAppsServer(c.Context()); err != nil {
if err := o.RunCozyServer(c.Context()); err != nil {
return err
}
return nil
@@ -101,22 +106,19 @@ func NewCommandStartAppsServer(ctx context.Context, defaults *AppsServerOptions)
flags := cmd.Flags()
o.RecommendedOptions.AddFlags(flags)
// Add a flag for the config path
flags.StringVar(&o.ResourceConfigPath, "config", "config.yaml", "Path to the resource configuration file")
// The following lines demonstrate how to configure version compatibility and feature gates
// for the "Apps" component according to KEP-4330.
// for the "Cozy" component according to KEP-4330.
// Create a default version object for the "Apps" component.
defaultAppsVersion := "1.1"
// Register the "Apps" component in the global component registry,
// Create a default version object for the "Cozy" component.
defaultCozyVersion := "1.1"
// Register the "Cozy" component in the global component registry,
// associating it with its effective version and feature gate configuration.
_, appsFeatureGate := utilversionpkg.DefaultComponentGlobalsRegistry.ComponentGlobalsOrRegister(
apiserver.AppsComponentName, utilversionpkg.NewEffectiveVersion(defaultAppsVersion),
featuregate.NewVersionedFeatureGate(version.MustParse(defaultAppsVersion)),
apiserver.CozyComponentName, utilversionpkg.NewEffectiveVersion(defaultCozyVersion),
featuregate.NewVersionedFeatureGate(version.MustParse(defaultCozyVersion)),
)
// Add feature gate specifications for the "Apps" component.
// Add feature gate specifications for the "Cozy" component.
utilruntime.Must(appsFeatureGate.AddVersioned(map[featuregate.Feature]featuregate.VersionedSpecs{
// Example of adding feature gates:
// "FeatureName": {{"v1", true}, {"v2", false}},
@@ -129,9 +131,9 @@ func NewCommandStartAppsServer(ctx context.Context, defaults *AppsServerOptions)
utilfeature.DefaultMutableFeatureGate,
)
// Set the version emulation mapping from the "Apps" component to the kube component.
// Set the version emulation mapping from the "Cozy" component to the kube component.
utilruntime.Must(utilversionpkg.DefaultComponentGlobalsRegistry.SetEmulationVersionMapping(
apiserver.AppsComponentName, utilversionpkg.DefaultKubeComponent, AppsVersionToKubeVersion,
apiserver.CozyComponentName, utilversionpkg.DefaultKubeComponent, CozyVersionToKubeVersion,
))
// Add flags from the global component registry.
@@ -141,26 +143,68 @@ func NewCommandStartAppsServer(ctx context.Context, defaults *AppsServerOptions)
}
// Complete fills in the fields that are not set
func (o *AppsServerOptions) Complete() error {
// Load the configuration file
cfg, err := config.LoadConfig(o.ResourceConfigPath)
if err != nil {
return fmt.Errorf("failed to load config from %s: %v", o.ResourceConfigPath, err)
func (o *CozyServerOptions) Complete() error {
scheme := runtime.NewScheme()
if err := v1alpha1.AddToScheme(scheme); err != nil {
return fmt.Errorf("failed to register types: %w", err)
}
o.ResourceConfig = cfg
cfg, err := clientcmd.BuildConfigFromFlags("", "")
if err != nil {
return fmt.Errorf("failed to get kubeconfig: %w", err)
}
o.Client, err = client.New(cfg, client.Options{Scheme: scheme})
if err != nil {
return fmt.Errorf("client initialization failed: %w", err)
}
crdList := &v1alpha1.CozystackResourceDefinitionList{}
if err := o.Client.List(context.Background(), crdList); err != nil {
return fmt.Errorf("failed to list CozystackResourceDefinitions: %w", err)
}
// Convert to ResourceConfig
o.ResourceConfig = &config.ResourceConfig{}
for _, crd := range crdList.Items {
resource := config.Resource{
Application: config.ApplicationConfig{
Kind: crd.Spec.Application.Kind,
Singular: crd.Spec.Application.Singular,
Plural: crd.Spec.Application.Plural,
ShortNames: []string{}, // TODO: implement shortnames
OpenAPISchema: crd.Spec.Application.OpenAPISchema,
},
Release: config.ReleaseConfig{
Prefix: crd.Spec.Release.Prefix,
Labels: crd.Spec.Release.Labels,
Chart: config.ChartConfig{
Name: crd.Spec.Release.Chart.Name,
SourceRef: config.SourceRefConfig{
Kind: crd.Spec.Release.Chart.SourceRef.Kind,
Name: crd.Spec.Release.Chart.SourceRef.Name,
Namespace: crd.Spec.Release.Chart.SourceRef.Namespace,
},
},
},
}
o.ResourceConfig.Resources = append(o.ResourceConfig.Resources, resource)
}
return nil
}
// Validate checks the correctness of the options
func (o AppsServerOptions) Validate(args []string) error {
func (o CozyServerOptions) Validate(args []string) error {
var allErrors []error
allErrors = append(allErrors, o.RecommendedOptions.Validate()...)
allErrors = append(allErrors, utilversionpkg.DefaultComponentGlobalsRegistry.Validate()...)
return utilerrors.NewAggregate(allErrors)
}
// Config returns the configuration for the API server based on AppsServerOptions
func (o *AppsServerOptions) Config() (*apiserver.Config, error) {
// Config returns the configuration for the API server based on CozyServerOptions
func (o *CozyServerOptions) Config() (*apiserver.Config, error) {
// TODO: set the "real" external address
if err := o.RecommendedOptions.SecureServing.MaybeDefaultWithSelfSignedCerts(
"localhost", o.AlternateDNS, []net.IP{netutils.ParseIPSloppy("127.0.0.1")},
@@ -168,8 +212,11 @@ func (o *AppsServerOptions) Config() (*apiserver.Config, error) {
return nil, fmt.Errorf("error creating self-signed certificates: %v", err)
}
// First, register the dynamic types
err := v1alpha1.RegisterDynamicTypes(apiserver.Scheme, o.ResourceConfig)
// Register *compile-time* resources first.
corev1alpha1.RegisterStaticTypes(apiserver.Scheme)
// Register *run-time* resources (from the users config file).
err := appsv1alpha1.RegisterDynamicTypes(apiserver.Scheme, o.ResourceConfig)
if err != nil {
return nil, fmt.Errorf("failed to register dynamic types: %v", err)
}
@@ -196,14 +243,14 @@ func (o *AppsServerOptions) Config() (*apiserver.Config, error) {
kindSchemas[r.Application.Kind] = r.Application.OpenAPISchema
}
serverConfig.OpenAPIConfig.Info.Title = "Apps"
serverConfig.OpenAPIConfig.Info.Title = "Cozy"
serverConfig.OpenAPIConfig.Info.Version = version
serverConfig.OpenAPIConfig.PostProcessSpec = buildPostProcessV2(kindSchemas)
serverConfig.OpenAPIV3Config = genericapiserver.DefaultOpenAPIV3Config(
sampleopenapi.GetOpenAPIDefinitions, openapi.NewDefinitionNamer(apiserver.Scheme),
)
serverConfig.OpenAPIV3Config.Info.Title = "Apps"
serverConfig.OpenAPIV3Config.Info.Title = "Cozy"
serverConfig.OpenAPIV3Config.Info.Version = version
serverConfig.OpenAPIV3Config.PostProcessSpec = buildPostProcessV3(kindSchemas)
@@ -212,7 +259,7 @@ func (o *AppsServerOptions) Config() (*apiserver.Config, error) {
utilversionpkg.DefaultKubeComponent,
)
serverConfig.EffectiveVersion = utilversionpkg.DefaultComponentGlobalsRegistry.EffectiveVersionFor(
apiserver.AppsComponentName,
apiserver.CozyComponentName,
)
if err := o.RecommendedOptions.ApplyTo(serverConfig); err != nil {
@@ -226,8 +273,8 @@ func (o *AppsServerOptions) Config() (*apiserver.Config, error) {
return config, nil
}
// RunAppsServer launches a new AppsServer based on AppsServerOptions
func (o AppsServerOptions) RunAppsServer(ctx context.Context) error {
// RunCozyServer launches a new CozyServer based on CozyServerOptions
func (o CozyServerOptions) RunCozyServer(ctx context.Context) error {
config, err := o.Config()
if err != nil {
return err
@@ -246,8 +293,8 @@ func (o AppsServerOptions) RunAppsServer(ctx context.Context) error {
return server.GenericAPIServer.PrepareRun().RunWithContext(ctx)
}
// AppsVersionToKubeVersion defines the version mapping between the Apps component and kube
func AppsVersionToKubeVersion(ver *version.Version) *version.Version {
// CozyVersionToKubeVersion defines the version mapping between the Cozy component and kube
func CozyVersionToKubeVersion(ver *version.Version) *version.Version {
if ver.Major() != 1 {
return nil
}

View File

@@ -25,7 +25,7 @@ import (
"github.com/stretchr/testify/assert"
)
func TestAppsEmulationVersionToKubeEmulationVersion(t *testing.T) {
func TestCozyEmulationVersionToKubeEmulationVersion(t *testing.T) {
defaultKubeEffectiveVersion := utilversion.DefaultKubeEffectiveVersion()
testCases := []struct {
@@ -61,7 +61,7 @@ func TestAppsEmulationVersionToKubeEmulationVersion(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.desc, func(t *testing.T) {
mappedKubeEmulationVer := AppsVersionToKubeVersion(tc.appsEmulationVer)
mappedKubeEmulationVer := CozyVersionToKubeVersion(tc.appsEmulationVer)
assert.True(t, mappedKubeEmulationVer.EqualTo(tc.expectedKubeEmulationVer))
})
}

View File

@@ -16,13 +16,6 @@ limitations under the License.
package config
import (
"fmt"
"os"
"gopkg.in/yaml.v2"
)
// ResourceConfig represents the structure of the configuration file.
type ResourceConfig struct {
Resources []Resource `yaml:"resources"`
@@ -62,33 +55,3 @@ type SourceRefConfig struct {
Name string `yaml:"name"`
Namespace string `yaml:"namespace"`
}
// LoadConfig loads the configuration from the specified path and validates it.
func LoadConfig(path string) (*ResourceConfig, error) {
data, err := os.ReadFile(path)
if err != nil {
return nil, err
}
var config ResourceConfig
if err := yaml.Unmarshal(data, &config); err != nil {
return nil, err
}
// Validate the configuration.
for i, res := range config.Resources {
if res.Application.Kind == "" {
return nil, fmt.Errorf("resource at index %d has an empty kind", i)
}
if res.Application.Plural == "" {
return nil, fmt.Errorf("resource at index %d has an empty plural", i)
}
if res.Release.Chart.Name == "" {
return nil, fmt.Errorf("resource at index %d has an empty chart name in release", i)
}
if res.Release.Chart.SourceRef.Kind == "" || res.Release.Chart.SourceRef.Name == "" || res.Release.Chart.SourceRef.Namespace == "" {
return nil, fmt.Errorf("resource at index %d has an incomplete sourceRef for chart in release", i)
}
}
return &config, nil
}

View File

@@ -30,9 +30,13 @@ import (
func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenAPIDefinition {
return map[string]common.OpenAPIDefinition{
"github.com/cozystack/cozystack/pkg/apis/apps/v1alpha1.Application": schema_pkg_apis_apps_v1alpha1_Application(ref),
"github.com/cozystack/cozystack/pkg/apis/apps/v1alpha1.ApplicationList": schema_pkg_apis_apps_v1alpha1_ApplicationList(ref),
"github.com/cozystack/cozystack/pkg/apis/apps/v1alpha1.ApplicationStatus": schema_pkg_apis_apps_v1alpha1_ApplicationStatus(ref),
"github.com/cozystack/cozystack/pkg/apis/apps/v1alpha1.Application": schema_pkg_apis_apps_v1alpha1_Application(ref),
"github.com/cozystack/cozystack/pkg/apis/apps/v1alpha1.ApplicationList": schema_pkg_apis_apps_v1alpha1_ApplicationList(ref),
"github.com/cozystack/cozystack/pkg/apis/apps/v1alpha1.ApplicationStatus": schema_pkg_apis_apps_v1alpha1_ApplicationStatus(ref),
"github.com/cozystack/cozystack/pkg/apis/core/v1alpha1.TenantNamespace": schema_pkg_apis_core_v1alpha1_TenantNamespace(ref),
"github.com/cozystack/cozystack/pkg/apis/core/v1alpha1.TenantNamespaceList": schema_pkg_apis_core_v1alpha1_TenantNamespaceList(ref),
"github.com/cozystack/cozystack/pkg/apis/core/v1alpha1.TenantSecret": schema_pkg_apis_core_v1alpha1_TenantSecret(ref),
"github.com/cozystack/cozystack/pkg/apis/core/v1alpha1.TenantSecretList": schema_pkg_apis_core_v1alpha1_TenantSecretList(ref),
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1.ConversionRequest": schema_pkg_apis_apiextensions_v1_ConversionRequest(ref),
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1.ConversionResponse": schema_pkg_apis_apiextensions_v1_ConversionResponse(ref),
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1.ConversionReview": schema_pkg_apis_apiextensions_v1_ConversionReview(ref),
@@ -252,6 +256,208 @@ func schema_pkg_apis_apps_v1alpha1_ApplicationStatus(ref common.ReferenceCallbac
}
}
func schema_pkg_apis_core_v1alpha1_TenantNamespace(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
Description: "TenantNamespace is a thin wrapper around ObjectMeta. It has no spec/status because it merely reflects an existing Namespace object.",
Type: []string{"object"},
Properties: map[string]spec.Schema{
"kind": {
SchemaProps: spec.SchemaProps{
Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
Type: []string{"string"},
Format: "",
},
},
"apiVersion": {
SchemaProps: spec.SchemaProps{
Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
Type: []string{"string"},
Format: "",
},
},
"metadata": {
SchemaProps: spec.SchemaProps{
Default: map[string]interface{}{},
Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"),
},
},
},
},
},
Dependencies: []string{
"k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"},
}
}
func schema_pkg_apis_core_v1alpha1_TenantNamespaceList(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
Description: "TenantNamespaceList is the list variant for TenantNamespace.",
Type: []string{"object"},
Properties: map[string]spec.Schema{
"kind": {
SchemaProps: spec.SchemaProps{
Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
Type: []string{"string"},
Format: "",
},
},
"apiVersion": {
SchemaProps: spec.SchemaProps{
Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
Type: []string{"string"},
Format: "",
},
},
"metadata": {
SchemaProps: spec.SchemaProps{
Default: map[string]interface{}{},
Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"),
},
},
"items": {
SchemaProps: spec.SchemaProps{
Type: []string{"array"},
Items: &spec.SchemaOrArray{
Schema: &spec.Schema{
SchemaProps: spec.SchemaProps{
Default: map[string]interface{}{},
Ref: ref("github.com/cozystack/cozystack/pkg/apis/core/v1alpha1.TenantNamespace"),
},
},
},
},
},
},
Required: []string{"items"},
},
},
Dependencies: []string{
"github.com/cozystack/cozystack/pkg/apis/core/v1alpha1.TenantNamespace", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"},
}
}
func schema_pkg_apis_core_v1alpha1_TenantSecret(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
Type: []string{"object"},
Properties: map[string]spec.Schema{
"kind": {
SchemaProps: spec.SchemaProps{
Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
Type: []string{"string"},
Format: "",
},
},
"apiVersion": {
SchemaProps: spec.SchemaProps{
Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
Type: []string{"string"},
Format: "",
},
},
"metadata": {
SchemaProps: spec.SchemaProps{
Default: map[string]interface{}{},
Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"),
},
},
"type": {
SchemaProps: spec.SchemaProps{
Description: "Same semantics as core/v1 Secret.",
Type: []string{"string"},
Format: "",
},
},
"data": {
SchemaProps: spec.SchemaProps{
Type: []string{"object"},
AdditionalProperties: &spec.SchemaOrBool{
Allows: true,
Schema: &spec.Schema{
SchemaProps: spec.SchemaProps{
Type: []string{"string"},
Format: "byte",
},
},
},
},
},
"stringData": {
SchemaProps: spec.SchemaProps{
Type: []string{"object"},
AdditionalProperties: &spec.SchemaOrBool{
Allows: true,
Schema: &spec.Schema{
SchemaProps: spec.SchemaProps{
Default: "",
Type: []string{"string"},
Format: "",
},
},
},
},
},
},
},
},
Dependencies: []string{
"k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"},
}
}
func schema_pkg_apis_core_v1alpha1_TenantSecretList(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
Type: []string{"object"},
Properties: map[string]spec.Schema{
"kind": {
SchemaProps: spec.SchemaProps{
Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
Type: []string{"string"},
Format: "",
},
},
"apiVersion": {
SchemaProps: spec.SchemaProps{
Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
Type: []string{"string"},
Format: "",
},
},
"metadata": {
SchemaProps: spec.SchemaProps{
Default: map[string]interface{}{},
Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"),
},
},
"items": {
SchemaProps: spec.SchemaProps{
Type: []string{"array"},
Items: &spec.SchemaOrArray{
Schema: &spec.Schema{
SchemaProps: spec.SchemaProps{
Default: map[string]interface{}{},
Ref: ref("github.com/cozystack/cozystack/pkg/apis/core/v1alpha1.TenantSecret"),
},
},
},
},
},
},
Required: []string{"items"},
},
},
Dependencies: []string{
"github.com/cozystack/cozystack/pkg/apis/core/v1alpha1.TenantSecret", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"},
}
}
func schema_pkg_apis_apiextensions_v1_ConversionRequest(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{

View File

@@ -271,7 +271,6 @@ func (r *REST) List(ctx context.Context, options *metainternalversion.ListOption
klog.Errorf("Invalid field selector: %v", err)
return nil, fmt.Errorf("invalid field selector: %v", err)
}
// Check if selector is for metadata.name
if name, exists := fs.RequiresExactMatch("metadata.name"); exists {
// Convert Application name to HelmRelease name
@@ -321,17 +320,8 @@ func (r *REST) List(ctx context.Context, options *metainternalversion.ListOption
return nil, err
}
// Initialize empty Application list
appList := &appsv1alpha1.ApplicationList{
TypeMeta: metav1.TypeMeta{
APIVersion: "apps.cozystack.io/v1alpha1",
Kind: "ApplicationList",
},
ListMeta: metav1.ListMeta{
ResourceVersion: hrList.GetResourceVersion(),
},
Items: []appsv1alpha1.Application{},
}
// Initialize unstructured items array
items := make([]unstructured.Unstructured, 0)
// Iterate over HelmReleases and convert to Applications
for _, hr := range hrList.Items {
@@ -369,7 +359,6 @@ func (r *REST) List(ctx context.Context, options *metainternalversion.ListOption
klog.Errorf("Invalid field selector: %v", err)
continue
}
fieldsSet := fields.Set{
"metadata.name": app.Name,
"metadata.namespace": app.Namespace,
@@ -379,10 +368,23 @@ func (r *REST) List(ctx context.Context, options *metainternalversion.ListOption
}
}
appList.Items = append(appList.Items, app)
// Convert Application to unstructured
unstructuredApp, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&app)
if err != nil {
klog.Errorf("Error converting Application %s to unstructured: %v", app.Name, err)
continue
}
items = append(items, unstructured.Unstructured{Object: unstructuredApp})
}
klog.V(6).Infof("Successfully listed %d Application resources in namespace %s", len(appList.Items), namespace)
// Explicitly set apiVersion and kind in unstructured object
appList := &unstructured.UnstructuredList{}
appList.SetAPIVersion("apps.cozystack.io/v1alpha1")
appList.SetKind(r.kindName + "List")
appList.SetResourceVersion(hrList.GetResourceVersion())
appList.Items = items
klog.V(6).Infof("Successfully listed %d Application resources in namespace %s", len(items), namespace)
return appList, nil
}
@@ -1036,6 +1038,19 @@ func (r *REST) ConvertToTable(ctx context.Context, object runtime.Object, tableO
case *appsv1alpha1.Application:
table = r.buildTableFromApplication(*obj)
table.ListMeta.ResourceVersion = obj.GetResourceVersion()
case *unstructured.UnstructuredList:
apps := make([]appsv1alpha1.Application, 0, len(obj.Items))
for _, u := range obj.Items {
var a appsv1alpha1.Application
err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, &a)
if err != nil {
klog.Errorf("Failed to convert Unstructured to Application: %v", err)
continue
}
apps = append(apps, a)
}
table = r.buildTableFromApplications(apps)
table.ListMeta.ResourceVersion = obj.GetResourceVersion()
case *unstructured.Unstructured:
var app appsv1alpha1.Application
err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.UnstructuredContent(), &app)
@@ -1067,7 +1082,6 @@ func (r *REST) ConvertToTable(ctx context.Context, object runtime.Object, tableO
}
klog.V(6).Infof("ConvertToTable: returning table with %d rows", len(table.Rows))
return &table, nil
}

View File

@@ -0,0 +1,363 @@
// SPDX-License-Identifier: Apache-2.0
// TenantNamespace registry: read-only view over Namespaces whose names start
// with “tenant-”.
package tenantnamespace
import (
"context"
"fmt"
"math"
"net/http"
"strings"
"sync"
"time"
authorizationv1 "k8s.io/api/authorization/v1"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metainternal "k8s.io/apimachinery/pkg/apis/meta/internalversion"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/duration"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/apiserver/pkg/registry/rest"
authorizationv1client "k8s.io/client-go/kubernetes/typed/authorization/v1"
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
"k8s.io/klog/v2"
corev1alpha1 "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1"
)
const (
prefix = "tenant-"
singularName = "tenantnamespace"
)
// -----------------------------------------------------------------------------
// REST storage
// -----------------------------------------------------------------------------
var (
_ rest.Lister = &REST{}
_ rest.Getter = &REST{}
_ rest.Watcher = &REST{}
_ rest.TableConvertor = &REST{}
_ rest.Scoper = &REST{}
_ rest.SingularNameProvider = &REST{}
)
type REST struct {
core corev1client.CoreV1Interface
authClient authorizationv1client.AuthorizationV1Interface
maxWorkers int
gvr schema.GroupVersionResource
}
func NewREST(
coreCli corev1client.CoreV1Interface,
authCli authorizationv1client.AuthorizationV1Interface,
maxWorkers int,
) *REST {
return &REST{
core: coreCli,
authClient: authCli,
maxWorkers: maxWorkers,
gvr: schema.GroupVersionResource{
Group: corev1alpha1.GroupName,
Version: "v1alpha1",
Resource: "tenantnamespaces",
},
}
}
// -----------------------------------------------------------------------------
// Basic meta
// -----------------------------------------------------------------------------
func (*REST) NamespaceScoped() bool { return false }
func (*REST) New() runtime.Object { return &corev1alpha1.TenantNamespace{} }
func (*REST) NewList() runtime.Object {
return &corev1alpha1.TenantNamespaceList{}
}
func (*REST) Kind() string { return "TenantNamespace" }
func (r *REST) GroupVersionKind(_ schema.GroupVersion) schema.GroupVersionKind {
return r.gvr.GroupVersion().WithKind("TenantNamespace")
}
func (*REST) GetSingularName() string { return singularName }
// -----------------------------------------------------------------------------
// Lister / Getter
// -----------------------------------------------------------------------------
func (r *REST) List(
ctx context.Context,
_ *metainternal.ListOptions,
) (runtime.Object, error) {
nsList, err := r.core.Namespaces().List(ctx, metav1.ListOptions{})
if err != nil {
return nil, err
}
var tenantNames []string
for i := range nsList.Items {
if strings.HasPrefix(nsList.Items[i].Name, prefix) {
tenantNames = append(tenantNames, nsList.Items[i].Name)
}
}
allowed, err := r.filterAccessible(ctx, tenantNames)
if err != nil {
return nil, err
}
return r.makeList(nsList, allowed), nil
}
func (r *REST) Get(
ctx context.Context,
name string,
opts *metav1.GetOptions,
) (runtime.Object, error) {
if !strings.HasPrefix(name, prefix) {
return nil, apierrors.NewNotFound(r.gvr.GroupResource(), name)
}
ns, err := r.core.Namespaces().Get(ctx, name, *opts)
if err != nil {
return nil, err
}
return &corev1alpha1.TenantNamespace{
TypeMeta: metav1.TypeMeta{
APIVersion: corev1alpha1.SchemeGroupVersion.String(),
Kind: "TenantNamespace",
},
ObjectMeta: metav1.ObjectMeta{
Name: ns.Name,
UID: ns.UID,
ResourceVersion: ns.ResourceVersion,
CreationTimestamp: ns.CreationTimestamp,
Labels: ns.Labels,
Annotations: ns.Annotations,
},
}, nil
}
// -----------------------------------------------------------------------------
// Watcher
// -----------------------------------------------------------------------------
func (r *REST) Watch(ctx context.Context, opts *metainternal.ListOptions) (watch.Interface, error) {
nsWatch, err := r.core.Namespaces().Watch(ctx, metav1.ListOptions{
Watch: true,
ResourceVersion: opts.ResourceVersion,
})
if err != nil {
return nil, err
}
events := make(chan watch.Event)
pw := watch.NewProxyWatcher(events)
go func() {
defer pw.Stop()
for ev := range nsWatch.ResultChan() {
ns, ok := ev.Object.(*corev1.Namespace)
if !ok || !strings.HasPrefix(ns.Name, prefix) {
continue
}
out := &corev1alpha1.TenantNamespace{
TypeMeta: metav1.TypeMeta{
APIVersion: corev1alpha1.SchemeGroupVersion.String(),
Kind: "TenantNamespace",
},
ObjectMeta: metav1.ObjectMeta{
Name: ns.Name,
UID: ns.UID,
ResourceVersion: ns.ResourceVersion,
CreationTimestamp: ns.CreationTimestamp,
Labels: ns.Labels,
Annotations: ns.Annotations,
},
}
events <- watch.Event{Type: ev.Type, Object: out}
}
}()
return pw, nil
}
// -----------------------------------------------------------------------------
// TableConvertor
// -----------------------------------------------------------------------------
func (r *REST) ConvertToTable(_ context.Context, obj runtime.Object, _ runtime.Object) (*metav1.Table, error) {
now := time.Now()
row := func(o *corev1alpha1.TenantNamespace) metav1.TableRow {
return metav1.TableRow{
Cells: []interface{}{o.Name, duration.HumanDuration(now.Sub(o.CreationTimestamp.Time))},
Object: runtime.RawExtension{Object: o},
}
}
tbl := &metav1.Table{
TypeMeta: metav1.TypeMeta{APIVersion: "meta.k8s.io/v1", Kind: "Table"},
ColumnDefinitions: []metav1.TableColumnDefinition{
{Name: "NAME", Type: "string"},
{Name: "AGE", Type: "string"},
},
}
switch v := obj.(type) {
case *corev1alpha1.TenantNamespaceList:
for i := range v.Items {
tbl.Rows = append(tbl.Rows, row(&v.Items[i]))
}
tbl.ListMeta.ResourceVersion = v.ListMeta.ResourceVersion
case *corev1alpha1.TenantNamespace:
tbl.Rows = append(tbl.Rows, row(v))
tbl.ListMeta.ResourceVersion = v.ResourceVersion
default:
return nil, notAcceptable{r.gvr.GroupResource(), fmt.Sprintf("unexpected %T", obj)}
}
return tbl, nil
}
// -----------------------------------------------------------------------------
// Helpers
// -----------------------------------------------------------------------------
func (r *REST) makeList(src *corev1.NamespaceList, allowed []string) *corev1alpha1.TenantNamespaceList {
set := map[string]struct{}{}
for _, n := range allowed {
set[n] = struct{}{}
}
out := &corev1alpha1.TenantNamespaceList{
TypeMeta: metav1.TypeMeta{
APIVersion: corev1alpha1.SchemeGroupVersion.String(),
Kind: "TenantNamespaceList",
},
ListMeta: metav1.ListMeta{ResourceVersion: src.ResourceVersion},
}
for i := range src.Items {
ns := &src.Items[i]
if _, ok := set[ns.Name]; !ok {
continue
}
out.Items = append(out.Items, corev1alpha1.TenantNamespace{
TypeMeta: metav1.TypeMeta{
APIVersion: corev1alpha1.SchemeGroupVersion.String(),
Kind: "TenantNamespace",
},
ObjectMeta: metav1.ObjectMeta{
Name: ns.Name,
UID: ns.UID,
ResourceVersion: ns.ResourceVersion,
CreationTimestamp: ns.CreationTimestamp,
Labels: ns.Labels,
Annotations: ns.Annotations,
},
})
}
return out
}
func (r *REST) filterAccessible(
ctx context.Context,
names []string,
) ([]string, error) {
workers := int(math.Min(float64(r.maxWorkers), float64(len(names))))
type job struct{ name string }
type res struct {
name string
allowed bool
err error
}
jobs := make(chan job, workers)
out := make(chan res, workers)
var wg sync.WaitGroup
for i := 0; i < workers; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for j := range jobs {
ok, err := r.sar(ctx, j.name)
out <- res{j.name, ok, err}
}
}()
}
go func() { wg.Wait(); close(out) }()
go func() {
for _, n := range names {
jobs <- job{n}
}
close(jobs)
}()
var allowed []string
for r := range out {
if r.err != nil {
klog.Errorf("SAR failed for %s: %v", r.name, r.err)
continue
}
if r.allowed {
allowed = append(allowed, r.name)
}
}
return allowed, nil
}
func (r *REST) sar(ctx context.Context, ns string) (bool, error) {
u, ok := request.UserFrom(ctx)
if !ok || u == nil {
return false, fmt.Errorf("user missing in context")
}
sar := &authorizationv1.SubjectAccessReview{
Spec: authorizationv1.SubjectAccessReviewSpec{
User: u.GetName(),
Groups: u.GetGroups(),
ResourceAttributes: &authorizationv1.ResourceAttributes{
Group: "cozystack.io",
Resource: "workloadmonitors",
Verb: "get",
Namespace: ns,
},
},
}
rsp, err := r.authClient.SubjectAccessReviews().
Create(ctx, sar, metav1.CreateOptions{})
if err != nil {
return false, err
}
return rsp.Status.Allowed, nil
}
// -----------------------------------------------------------------------------
// Boiler-plate
// -----------------------------------------------------------------------------
func (*REST) Destroy() {}
type notAcceptable struct {
resource schema.GroupResource
message string
}
func (e notAcceptable) Error() string { return e.message }
func (e notAcceptable) Status() metav1.Status {
return metav1.Status{
Status: metav1.StatusFailure,
Code: http.StatusNotAcceptable,
Reason: metav1.StatusReason("NotAcceptable"),
Message: e.message,
}
}

View File

@@ -0,0 +1,456 @@
// SPDX-License-Identifier: Apache-2.0
// TenantSecret registry namespaced view over Secrets labelled
// “cozystack.io/ui=true”. Internal labels/annotations are hidden.
package tenantsecret
import (
"context"
"encoding/base64"
"fmt"
"net/http"
"sort"
"strings"
"time"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metainternal "k8s.io/apimachinery/pkg/apis/meta/internalversion"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/selection"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/duration"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/apiserver/pkg/registry/rest"
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
corev1alpha1 "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1"
)
// -----------------------------------------------------------------------------
// Constants & helpers
// -----------------------------------------------------------------------------
const (
uiLabelKey = "cozystack.io/ui"
uiLabelValue = "true"
systemLabelPrefix = "internal.cozystack.io/"
systemAnnotPrefix = "internal.cozystack.io/"
singularName = "tenantsecret"
kindTenantSecret = "TenantSecret"
kindTenantSecretList = "TenantSecretList"
)
func stripInternal(m map[string]string) map[string]string {
if m == nil {
return nil
}
out := make(map[string]string, len(m))
for k, v := range m {
if k == uiLabelKey ||
strings.HasPrefix(k, systemLabelPrefix) ||
strings.HasPrefix(k, systemAnnotPrefix) {
continue
}
out[k] = v
}
return out
}
func encodeStringData(sd map[string]string) map[string][]byte {
if len(sd) == 0 {
return nil
}
out := make(map[string][]byte, len(sd))
for k, v := range sd {
out[k] = []byte(v)
}
return out
}
func decodeStringData(d map[string][]byte) map[string]string {
if len(d) == 0 {
return nil
}
out := make(map[string]string, len(d))
for k, v := range d {
out[k] = base64.StdEncoding.EncodeToString(v)
}
return out
}
func secretToTenant(sec *corev1.Secret) *corev1alpha1.TenantSecret {
return &corev1alpha1.TenantSecret{
TypeMeta: metav1.TypeMeta{
APIVersion: corev1alpha1.SchemeGroupVersion.String(),
Kind: kindTenantSecret,
},
ObjectMeta: metav1.ObjectMeta{
Name: sec.Name,
Namespace: sec.Namespace,
UID: sec.UID,
ResourceVersion: sec.ResourceVersion,
CreationTimestamp: sec.CreationTimestamp,
Labels: stripInternal(sec.Labels),
Annotations: stripInternal(sec.Annotations),
},
Type: string(sec.Type),
Data: sec.Data,
StringData: decodeStringData(sec.Data),
}
}
func tenantToSecret(ts *corev1alpha1.TenantSecret, cur *corev1.Secret) *corev1.Secret {
var out corev1.Secret
if cur != nil {
out = *cur.DeepCopy()
}
out.TypeMeta = metav1.TypeMeta{APIVersion: "v1", Kind: "Secret"}
out.Name, out.Namespace = ts.Name, ts.Namespace
if out.Labels == nil {
out.Labels = map[string]string{}
}
out.Labels[uiLabelKey] = uiLabelValue
for k, v := range ts.Labels {
out.Labels[k] = v
}
if out.Annotations == nil {
out.Annotations = map[string]string{}
}
for k, v := range ts.Annotations {
out.Annotations[k] = v
}
if len(ts.Data) != 0 {
out.Data = ts.Data
} else if len(ts.StringData) != 0 {
out.Data = encodeStringData(ts.StringData)
}
out.Type = corev1.SecretType(ts.Type)
return &out
}
func nsFrom(ctx context.Context) (string, error) {
ns, ok := request.NamespaceFrom(ctx)
if !ok {
return "", apierrors.NewBadRequest("namespace required")
}
return ns, nil
}
// -----------------------------------------------------------------------------
// REST storage
// -----------------------------------------------------------------------------
var (
_ rest.Creater = &REST{}
_ rest.Getter = &REST{}
_ rest.Lister = &REST{}
_ rest.Updater = &REST{}
_ rest.Patcher = &REST{}
_ rest.GracefulDeleter = &REST{}
_ rest.Watcher = &REST{}
_ rest.TableConvertor = &REST{}
_ rest.Scoper = &REST{}
_ rest.SingularNameProvider = &REST{}
)
type REST struct {
core corev1client.CoreV1Interface
gvr schema.GroupVersionResource
}
func NewREST(coreCli corev1client.CoreV1Interface) *REST {
return &REST{
core: coreCli,
gvr: schema.GroupVersionResource{
Group: corev1alpha1.GroupName,
Version: "v1alpha1",
Resource: "tenantsecrets",
},
}
}
// -----------------------------------------------------------------------------
// Basic meta
// -----------------------------------------------------------------------------
func (*REST) NamespaceScoped() bool { return true }
func (*REST) New() runtime.Object { return &corev1alpha1.TenantSecret{} }
func (*REST) NewList() runtime.Object {
return &corev1alpha1.TenantSecretList{}
}
func (*REST) Kind() string { return kindTenantSecret }
func (r *REST) GroupVersionKind(_ schema.GroupVersion) schema.GroupVersionKind {
return r.gvr.GroupVersion().WithKind(kindTenantSecret)
}
func (*REST) GetSingularName() string { return singularName }
// -----------------------------------------------------------------------------
// CRUD
// -----------------------------------------------------------------------------
func (r *REST) Create(
ctx context.Context,
obj runtime.Object,
_ rest.ValidateObjectFunc,
opts *metav1.CreateOptions,
) (runtime.Object, error) {
in, ok := obj.(*corev1alpha1.TenantSecret)
if !ok {
return nil, fmt.Errorf("expected TenantSecret, got %T", obj)
}
sec := tenantToSecret(in, nil)
out, err := r.core.Secrets(sec.Namespace).Create(ctx, sec, *opts)
if err != nil {
return nil, err
}
return secretToTenant(out), nil
}
func (r *REST) Get(
ctx context.Context,
name string,
opts *metav1.GetOptions,
) (runtime.Object, error) {
ns, err := nsFrom(ctx)
if err != nil {
return nil, err
}
sec, err := r.core.Secrets(ns).Get(ctx, name, *opts)
if err != nil {
return nil, err
}
return secretToTenant(sec), nil
}
func (r *REST) List(ctx context.Context, opts *metainternal.ListOptions) (runtime.Object, error) {
ns, err := nsFrom(ctx)
if err != nil {
return nil, err
}
ls := labels.NewSelector()
req, _ := labels.NewRequirement(uiLabelKey, selection.Equals, []string{uiLabelValue})
ls = ls.Add(*req)
if opts.LabelSelector != nil {
if reqs, _ := opts.LabelSelector.Requirements(); len(reqs) > 0 {
ls = ls.Add(reqs...)
}
}
fieldSel := ""
if opts.FieldSelector != nil {
fieldSel = opts.FieldSelector.String()
}
list, err := r.core.Secrets(ns).List(ctx, metav1.ListOptions{
LabelSelector: ls.String(),
FieldSelector: fieldSel,
})
if err != nil {
return nil, err
}
out := &corev1alpha1.TenantSecretList{
TypeMeta: metav1.TypeMeta{
APIVersion: corev1alpha1.SchemeGroupVersion.String(),
Kind: kindTenantSecretList,
},
ListMeta: list.ListMeta,
}
for i := range list.Items {
out.Items = append(out.Items, *secretToTenant(&list.Items[i]))
}
sort.Slice(out.Items, func(i, j int) bool { return out.Items[i].Name < out.Items[j].Name })
return out, nil
}
func (r *REST) Update(
ctx context.Context,
name string,
objInfo rest.UpdatedObjectInfo,
_ rest.ValidateObjectFunc,
_ rest.ValidateObjectUpdateFunc,
forceCreate bool,
opts *metav1.UpdateOptions,
) (runtime.Object, bool, error) {
ns, err := nsFrom(ctx)
if err != nil {
return nil, false, err
}
cur, err := r.core.Secrets(ns).Get(ctx, name, metav1.GetOptions{})
if err != nil && !apierrors.IsNotFound(err) {
return nil, false, err
}
newObj, err := objInfo.UpdatedObject(ctx, nil)
if err != nil {
return nil, false, err
}
in := newObj.(*corev1alpha1.TenantSecret)
newSec := tenantToSecret(in, cur)
if cur == nil {
if !forceCreate && err == nil {
return nil, false, apierrors.NewNotFound(r.gvr.GroupResource(), name)
}
out, err := r.core.Secrets(ns).Create(ctx, newSec, metav1.CreateOptions{})
return secretToTenant(out), true, err
}
newSec.ResourceVersion = cur.ResourceVersion
out, err := r.core.Secrets(ns).Update(ctx, newSec, *opts)
return secretToTenant(out), false, err
}
func (r *REST) Delete(
ctx context.Context,
name string,
_ rest.ValidateObjectFunc,
opts *metav1.DeleteOptions,
) (runtime.Object, bool, error) {
ns, err := nsFrom(ctx)
if err != nil {
return nil, false, err
}
err = r.core.Secrets(ns).Delete(ctx, name, *opts)
return nil, err == nil, err
}
func (r *REST) Patch(
ctx context.Context,
name string,
pt types.PatchType,
data []byte,
opts *metav1.PatchOptions,
subresources ...string,
) (runtime.Object, error) {
ns, err := nsFrom(ctx)
if err != nil {
return nil, err
}
out, err := r.core.Secrets(ns).
Patch(ctx, name, pt, data, *opts, subresources...)
if err != nil {
return nil, err
}
// Ensure UI label is preserved
if out.Labels[uiLabelKey] != uiLabelValue {
out.Labels[uiLabelKey] = uiLabelValue
out, _ = r.core.Secrets(ns).Update(ctx, out, metav1.UpdateOptions{})
}
return secretToTenant(out), nil
}
// -----------------------------------------------------------------------------
// Watcher
// -----------------------------------------------------------------------------
func (r *REST) Watch(ctx context.Context, opts *metainternal.ListOptions) (watch.Interface, error) {
ns, err := nsFrom(ctx)
if err != nil {
return nil, err
}
ls := labels.Set{uiLabelKey: uiLabelValue}.AsSelector().String()
base, err := r.core.Secrets(ns).Watch(ctx, metav1.ListOptions{
Watch: true,
LabelSelector: ls,
ResourceVersion: opts.ResourceVersion,
})
if err != nil {
return nil, err
}
ch := make(chan watch.Event)
proxy := watch.NewProxyWatcher(ch)
go func() {
defer proxy.Stop()
for ev := range base.ResultChan() {
sec, ok := ev.Object.(*corev1.Secret)
if !ok || sec == nil {
continue
}
tenant := secretToTenant(sec)
ch <- watch.Event{
Type: ev.Type,
Object: tenant,
}
}
}()
return proxy, nil
}
// -----------------------------------------------------------------------------
// TableConvertor
// -----------------------------------------------------------------------------
func (r *REST) ConvertToTable(_ context.Context, obj runtime.Object, _ runtime.Object) (*metav1.Table, error) {
now := time.Now()
row := func(o *corev1alpha1.TenantSecret) metav1.TableRow {
return metav1.TableRow{
Cells: []interface{}{o.Name, o.Type, duration.HumanDuration(now.Sub(o.CreationTimestamp.Time))},
Object: runtime.RawExtension{Object: o},
}
}
tbl := &metav1.Table{
TypeMeta: metav1.TypeMeta{APIVersion: "meta.k8s.io/v1", Kind: "Table"},
ColumnDefinitions: []metav1.TableColumnDefinition{
{Name: "NAME", Type: "string"},
{Name: "TYPE", Type: "string"},
{Name: "AGE", Type: "string"},
},
}
switch v := obj.(type) {
case *corev1alpha1.TenantSecretList:
for i := range v.Items {
tbl.Rows = append(tbl.Rows, row(&v.Items[i]))
}
tbl.ListMeta.ResourceVersion = v.ListMeta.ResourceVersion
case *corev1alpha1.TenantSecret:
tbl.Rows = append(tbl.Rows, row(v))
tbl.ListMeta.ResourceVersion = v.ResourceVersion
default:
return nil, notAcceptable{r.gvr.GroupResource(), fmt.Sprintf("unexpected %T", obj)}
}
return tbl, nil
}
// -----------------------------------------------------------------------------
// Boiler-plate
// -----------------------------------------------------------------------------
func (*REST) Destroy() {}
type notAcceptable struct {
resource schema.GroupResource
message string
}
func (e notAcceptable) Error() string { return e.message }
func (e notAcceptable) Status() metav1.Status {
return metav1.Status{
Status: metav1.StatusFailure,
Code: http.StatusNotAcceptable,
Reason: metav1.StatusReason("NotAcceptable"),
Message: e.message,
}
}

View File

@@ -17,24 +17,17 @@ limitations under the License.
package registry
import (
"github.com/cozystack/cozystack/pkg/registry/apps/application"
"k8s.io/apimachinery/pkg/runtime/schema"
genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
"k8s.io/apiserver/pkg/registry/rest"
)
// REST implements a RESTStorage for API services against etcd
// REST is a thin wrapper around genericregistry.Store that also satisfies
// the GroupVersionKindProvider interface if callers need it later.
type REST struct {
*genericregistry.Store
GVK schema.GroupVersionKind
}
// Implement the GroupVersionKindProvider interface
func (r *REST) GroupVersionKind(containingGV schema.GroupVersion) schema.GroupVersionKind {
return r.GVK
}
// RESTInPeace creates REST for Application
func RESTInPeace(r *application.REST) rest.Storage {
return r
}
// RESTInPeace is a tiny helper so the call-site code reads nicely. It simply
// returns its argument, letting us defer (and centralise) any future error
// handling here.
func RESTInPeace(storage rest.Storage) rest.Storage { return storage }

View File

@@ -17,6 +17,8 @@ endif
# Get the name of the selected docker buildx builder
BUILDER ?= $(shell docker buildx inspect --bootstrap | head -n2 | awk '/^Name:/{print $$NF}')
# Get platforms supported by the builder
PLATFORM ?= $(shell docker buildx ls --format=json | jq -r 'select(.Name == "$(BUILDER)") | [.Nodes[].Platforms // []] | flatten | unique | map(select(test("^linux/amd64$$|^linux/arm64$$"))) | join(",")')
# Get platforms supported by the builder (only if PLATFORM is not provided)
ifeq ($(origin PLATFORM), undefined)
PLATFORM := $(shell docker buildx ls --format=json | jq -r 'select(.Name == "$(BUILDER)") | [.Nodes[].Platforms // []] | flatten | unique | map(select(test("^linux/amd64$$|^linux/arm64$$"))) | join(",")')
endif

10
scripts/migrations/17 Executable file
View File

@@ -0,0 +1,10 @@
#!/bin/sh
# Migration 17 --> 18
# Upgrade kubernetes.apps to new chart version
kubectl get kuberneteses.apps.cozystack.io -A --no-headers --output=custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name' | while read NAMESPACE NAME; do
kubectl patch kuberneteses.apps.cozystack.io -n "$NAMESPACE" "$NAME" --type merge -p '{"appVersion":"0.26.1"}'
done
# Write version to cozystack-version config
kubectl create configmap -n cozy-system cozystack-version --from-literal=version=18 --dry-run=client -o yaml | kubectl apply -f-