mirror of
https://github.com/cozystack/cozystack.git
synced 2026-10-23 03:27:50 +09:00
feat(bucket): add a ui flag to skip the s3manager web UI (#4881)
<!-- Thank you for making a contribution! Here are some tips for you: - Use Conventional Commits for the PR title: `type(scope): description` - Types: feat, fix, docs, style, refactor, perf, test, build, ci, chore - Scopes are not an exhaustive list — pick the most specific scope for the change and extend the list when a genuinely new area appears. Examples: - System components: dashboard, platform, operator, cilium, kube-ovn, linstor, fluxcd, cluster-api - Managed apps: postgres, mariadb, redis, kafka, clickhouse, virtual-machine, kubernetes - Development and maintenance: api, hack, tests, ci, docs, maintenance - Breaking changes: append `!` after type/scope (`feat(api)!: ...`) or add a `BREAKING CHANGE:` footer - If it's a work in progress, consider creating this PR as a draft. - Don't hesistate to ask for opinion and review in the community chats, even if it's still a draft. - Add the label `kind/backport` if it's a bugfix that needs to be backported to a previous version. --> ## What this PR does Adds a `ui` flag to the Bucket application. Every bucket currently ships an s3manager Deployment, its Service, and an Ingress or HTTPRoute on `<bucket>.<tenant host>`. Tenants that only use the S3 API pay for a pod per bucket and for one DNS name and TLS certificate per bucket, none of which they need. - `packages/apps/bucket`: new `ui` value (default `true`), passed through to the `bucket-system` HelmRelease. The dashboard Role drops its Ingress rule when the UI is off, since an empty `resourceNames` would widen it to every Ingress in the namespace. - `packages/system/bucket`: the Deployment, Service, Ingress and HTTPRoute render only when `ui` is true. With the UI off, the chart no longer requires the tenant apex, as the UI hostname was its only consumer there. - Regenerated `values.schema.json`, `README.md`, `types.go` and the `bucket-rd` ApplicationDefinition. The default keeps existing buckets unchanged. Setting `ui: false` on an existing bucket makes Helm delete the UI objects on the next upgrade; the cert-manager Certificate for the UI host is owned by the Ingress through ingress-shim and goes with it. Tested with `helm unittest` on both charts: new suites cover the default render, `ui: false` behind an Ingress and behind a Gateway, the empty-apex case, the value passthrough and the dashboard Role. The system-chart suite fails against the previous templates. ### Screenshots Not applicable: no dashboard change, only a new field in the Bucket form generated from the schema. ### Downstream repositories <!-- Cozystack is upstream for repositories that are NOT kept in sync with it automatically, and nothing in CI compares the two sides, so a change here can break them silently. Which change forces what, and which file to touch, is the trigger map in docs/agents/contributing.md under "Downstream Repositories". Walk it before you tick anything. IF YOU ARE AN AI AGENT OR AN LLM, THIS IS PART OF THE TASK, NOT A FORM TO FILL IN: 1. Walk the trigger map against the actual diff of this PR, file by file. Do not decide from the PR title or from your memory of what you changed. 2. For every repository you tick, open the follow-up PR there and link it on the same line. A ticked box with no link claims work that does not exist, which is worse than an empty box. Search that repository for an open PR or issue covering it first, and link that instead of filing a duplicate. 3. When the follow-up is out of scope, or needs a decision that is not yours to make, open an issue in that repository instead, link that, and say so in the PR body. Do not push a speculative PR into another repository just to fill a line here. 4. Do not tick "No downstream repository is affected" to make the checklist go away. If you are unsure, leave every box empty and say so in the PR body, so a human decides. --> Walked the trigger map against the diff. A new field in `packages/apps/bucket/values.schema.json` reaches the Terraform provider (schema, model, expand/flatten) and the website (the Bucket page is hand-written). Both follow-ups are issues rather than PRs, since they apply only once this PR is merged. - [ ] No downstream repository is affected by this change - [x] [cozystack/website](https://github.com/cozystack/website) - follow-up: cozystack/website#750 - [x] [cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack) - follow-up: cozystack/terraform-provider-cozystack#71 - [ ] [cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack) - follow-up: - [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up: - [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up: - [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) - follow-up: - [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) - follow-up: - [ ] [cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server) - follow-up: - [ ] [cozystack/external-apps-example](https://github.com/cozystack/external-apps-example) - follow-up: - [ ] [cozystack/examples](https://github.com/cozystack/examples) - follow-up: - [ ] [cozystack/community](https://github.com/cozystack/community) - follow-up: ### Release note <!-- Write a release note: - Explain what has changed internally and for users. - Start with the same `type(scope):` prefix as in the PR title - Follow the guidelines at https://github.com/kubernetes/community/blob/master/contributors/guide/release-notes.md. --> ```release-note feat(bucket): add a `ui` flag to the Bucket application. Set it to `false` to skip the s3manager web UI and its Service, Ingress or HTTPRoute, DNS name and TLS certificate. Defaults to `true`, so existing buckets are unchanged. ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added a `ui` option for bucket deployments. It is enabled by default and provides the S3 manager web UI at the tenant host. * Set `ui` to `false` to run a bucket without its web UI or the associated Service and Ingress or HTTPRoute. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
14 files changed
+149
-8
No files matched your search
Generated
+3
@@ -22,6 +22,9 @@ type ConfigSpec struct {
|
||||
// Selects a specific BucketClass by storage pool name.
|
||||
// +kubebuilder:default:=""
|
||||
StoragePool string `json:"storagePool,omitempty"`
|
||||
// Deploys the web UI (s3manager) with its Service and its Ingress or HTTPRoute at `<bucket>.<tenant host>`. Set to `false` to run the bucket without them.
|
||||
// +kubebuilder:default:=true
|
||||
Ui bool `json:"ui"`
|
||||
// Users configuration map.
|
||||
// +kubebuilder:default:={}
|
||||
Users map[string]User `json:"users,omitempty"`
|
||||
|
||||
@@ -4,10 +4,11 @@
|
||||
|
||||
### Parameters
|
||||
|
||||
| Name | Description | Type | Value |
|
||||
| ---------------------- | -------------------------------------------------------------------------- | ------------------- | ------- |
|
||||
| `locking` | Provisions bucket from the `-lock` BucketClass (with object lock enabled). | `bool` | `false` |
|
||||
| `storagePool` | Selects a specific BucketClass by storage pool name. | `string` | `""` |
|
||||
| `users` | Users configuration map. | `map[string]object` | `{}` |
|
||||
| `users[name].readonly` | Whether the user has read-only access. | `bool` | `false` |
|
||||
| Name | Description | Type | Value |
|
||||
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------- | ------- |
|
||||
| `locking` | Provisions bucket from the `-lock` BucketClass (with object lock enabled). | `bool` | `false` |
|
||||
| `storagePool` | Selects a specific BucketClass by storage pool name. | `string` | `""` |
|
||||
| `ui` | Deploys the web UI (s3manager) with its Service and its Ingress or HTTPRoute at `<bucket>.<tenant host>`. Set to `false` to run the bucket without them. | `bool` | `true` |
|
||||
| `users` | Users configuration map. | `map[string]object` | `{}` |
|
||||
| `users[name].readonly` | Whether the user has read-only access. | `bool` | `false` |
|
||||
|
||||
@@ -12,6 +12,7 @@ rules:
|
||||
- {{ $.Release.Name }}-{{ $name }}-credentials
|
||||
{{- end }}
|
||||
verbs: ["get", "list", "watch"]
|
||||
{{- if .Values.ui }}
|
||||
- apiGroups:
|
||||
- networking.k8s.io
|
||||
resources:
|
||||
@@ -19,6 +20,7 @@ rules:
|
||||
resourceNames:
|
||||
- {{ .Release.Name }}-ui
|
||||
verbs: ["get", "list", "watch"]
|
||||
{{- end }}
|
||||
---
|
||||
kind: RoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
|
||||
@@ -23,3 +23,4 @@ spec:
|
||||
values:
|
||||
bucketName: {{ .Release.Name }}
|
||||
users: {{ .Values.users | toJson }}
|
||||
ui: {{ .Values.ui }}
|
||||
@@ -0,0 +1,50 @@
|
||||
suite: bucket ui flag
|
||||
templates:
|
||||
- templates/helmrelease.yaml
|
||||
- templates/dashboard-resourcemap.yaml
|
||||
|
||||
release:
|
||||
name: bucket-my-bucket
|
||||
namespace: tenant-root
|
||||
|
||||
tests:
|
||||
- it: passes ui through to the bucket-system release, enabled by default
|
||||
template: templates/helmrelease.yaml
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.values.ui
|
||||
value: true
|
||||
|
||||
- it: passes ui=false through to the bucket-system release
|
||||
template: templates/helmrelease.yaml
|
||||
set:
|
||||
ui: false
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.values.ui
|
||||
value: false
|
||||
|
||||
- it: grants dashboard read access to the UI Ingress by default
|
||||
template: templates/dashboard-resourcemap.yaml
|
||||
documentIndex: 0
|
||||
asserts:
|
||||
- contains:
|
||||
path: rules
|
||||
content:
|
||||
apiGroups: ["networking.k8s.io"]
|
||||
resources: ["ingresses"]
|
||||
resourceNames: ["bucket-my-bucket-ui"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
|
||||
- it: drops the Ingress rule when ui is false
|
||||
template: templates/dashboard-resourcemap.yaml
|
||||
documentIndex: 0
|
||||
set:
|
||||
ui: false
|
||||
asserts:
|
||||
- lengthEqual:
|
||||
path: rules
|
||||
count: 1
|
||||
- notContains:
|
||||
path: rules[0].resources
|
||||
content: ingresses
|
||||
@@ -15,6 +15,11 @@
|
||||
"source": "storagepool"
|
||||
}
|
||||
},
|
||||
"ui": {
|
||||
"description": "Deploys the web UI (s3manager) with its Service and its Ingress or HTTPRoute at `\u003cbucket\u003e.\u003ctenant host\u003e`. Set to `false` to run the bucket without them.",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"users": {
|
||||
"description": "Users configuration map.",
|
||||
"type": "object",
|
||||
|
||||
@@ -5,6 +5,9 @@ locking: false
|
||||
## @x-cozystack-options {source: storagepool}
|
||||
storagePool: ""
|
||||
|
||||
## @param {bool} ui=true - Deploys the web UI (s3manager) with its Service and its Ingress or HTTPRoute at `<bucket>.<tenant host>`. Set to `false` to run the bucket without them.
|
||||
ui: true
|
||||
|
||||
## @typedef {struct} User - Bucket user configuration.
|
||||
## @field {bool} [readonly] - Whether the user has read-only access.
|
||||
|
||||
|
||||
+2
-2
@@ -8,7 +8,7 @@ spec:
|
||||
plural: buckets
|
||||
singular: bucket
|
||||
openAPISchema: |-
|
||||
{"title":"Chart Values","type":"object","properties":{"locking":{"description":"Provisions bucket from the `-lock` BucketClass (with object lock enabled).","type":"boolean","default":false},"storagePool":{"description":"Selects a specific BucketClass by storage pool name.","type":"string","default":"","x-cozystack-options":{"source":"storagepool"}},"users":{"description":"Users configuration map.","type":"object","default":{},"additionalProperties":{"type":"object","properties":{"readonly":{"description":"Whether the user has read-only access.","type":"boolean"}}}}}}
|
||||
{"title":"Chart Values","type":"object","properties":{"locking":{"description":"Provisions bucket from the `-lock` BucketClass (with object lock enabled).","type":"boolean","default":false},"storagePool":{"description":"Selects a specific BucketClass by storage pool name.","type":"string","default":"","x-cozystack-options":{"source":"storagepool"}},"ui":{"description":"Deploys the web UI (s3manager) with its Service and its Ingress or HTTPRoute at `<bucket>.<tenant host>`. Set to `false` to run the bucket without them.","type":"boolean","default":true},"users":{"description":"Users configuration map.","type":"object","default":{},"additionalProperties":{"type":"object","properties":{"readonly":{"description":"Whether the user has read-only access.","type":"boolean"}}}}}}
|
||||
release:
|
||||
prefix: bucket-
|
||||
labels:
|
||||
@@ -26,7 +26,7 @@ spec:
|
||||
tags:
|
||||
- storage
|
||||
icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxNDQiIGhlaWdodD0iMTQ0IiByeD0iMjQiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl82ODNfMzA5MSkiLz4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik03MiAzMC4xNjQxTDExNy45ODMgMzYuNzc4OVY0MC42NzM5QzExNy45ODMgNDYuNDY1MyA5Ny4zODYyIDUxLjEzMzIgNzEuOTgyNyA1MS4xMzMyQzQ2LjU3OTIgNTEuMTMzMiAyNiA0Ni40NjUzIDI2IDQwLjY3MzlWMzYuNDQzMUw3MiAzMC4xNjQxWk03MiA1OC4yNjc4QzkxLjIwODQgNTguMjY3OCAxMDcuNjU4IDU1LjU5ODYgMTE0LjU0NyA1MS44MDQ4TDExNi44MDMgNDguMTExTDExNy43MjMgNDQuNzUzVjQ4LjkxNzFMMTAyLjY3OSAxMTEuMDMzQzEwMi42NzkgMTE0Ljg5NSA4OC45NTMzIDExOCA3Mi4wMTcyIDExOEM1NS4wODEyIDExOCA0MS4zNzQzIDExNC44OTUgNDEuMzc0MyAxMTEuMDMzTDI2LjMzIDQ4LjkxNzFWNDQuODM2OUwyOS44MDA3IDUxLjkzODJDMzYuNzA2NSA1NS42NjUzIDUyLjk5OTcgNTguMjY3OCA3MiA1OC4yNjc4WiIgZmlsbD0iIzhDMzEyMyIvPgo8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTcyLjAwMDMgMjZDOTcuNDAzOCAyNiAxMTggMzAuNjgzOSAxMTggMzYuNDQyQzExOCA0Mi4yIDk3LjM4NjYgNDYuODUwNyA3Mi4wMDAzIDQ2Ljg1MDdDNDYuNjE0MSA0Ni44NTA3IDI2LjAxNzYgNDIuMjM0NSAyNi4wMTc2IDM2LjQ0MkMyNi4wMTc2IDMwLjY0OTQgNDYuNTk2OCAyNiA3Mi4wMDAzIDI2Wk03Mi4wMDAzIDU0LjEwMzdDOTUuNjg1NyA1NC4xMDM3IDExNS4xNzIgNTAuMDU4IDExNy43MDYgNDQuODE5N0wxMDIuNjYyIDEwNi45MzdDMTAyLjY2MiAxMTAuNzk5IDg4LjkzNjQgMTEzLjkwNSA3Mi4wMDAzIDExMy45MDVDNTUuMDY0MyAxMTMuOTA1IDQxLjMzOSAxMTAuODE2IDQxLjMzOSAxMDYuOTU0TDI2LjI5NTkgNDQuODM3QzI4Ljg0NjYgNTAuMDU4IDQ4LjMzMzMgNTQuMTAzNyA3Mi4wMDAzIDU0LjEwMzdaIiBmaWxsPSIjRTA1MjQzIi8+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNNjEuMTcyNSA2MC4wMjkzSDgxLjA5MjhWNzkuMTY3Nkg2MS4xNzI1VjYwLjAyOTNaTTQ1LjMzMDEgOTUuMzY4OEM0NS4zMzAxIDkwLjE0MiA0OS43MTA0IDg1LjkzNDIgNTUuMTUxMSA4NS45MzQyQzYwLjU5MTcgODUuOTM0MiA2NC45NzIxIDkwLjE0MiA2NC45NzIxIDk1LjM2ODhDNjQuOTcyMSAxMDAuNTk2IDYwLjU5MTcgMTA0LjgwMyA1NS4xNTExIDEwNC44MDNDNDkuNzEwNCAxMDQuODAzIDQ1LjMzMDEgMTAwLjU5NiA0NS4zMzAxIDk1LjM2ODhaTTk2LjQ0ODcgMTA0LjM2OEg3Ni43NzIyTDg2LjYxMDUgODYuNzczN0w5Ni40NDg3IDEwNC4zNjhaIiBmaWxsPSJ3aGl0ZSIvPgo8ZGVmcz4KPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDBfbGluZWFyXzY4M18zMDkxIiB4MT0iMCIgeTE9IjAiIHgyPSIxNTEiIHkyPSIxODAiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KPHN0b3Agc3RvcC1jb2xvcj0iI0ZGRjBFRSIvPgo8c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiNFQzg4N0QiLz4KPC9saW5lYXJHcmFkaWVudD4KPC9kZWZzPgo8L3N2Zz4K
|
||||
keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "locking"], ["spec", "storagePool"], ["spec", "users"]]
|
||||
keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "locking"], ["spec", "storagePool"], ["spec", "ui"], ["spec", "users"]]
|
||||
secrets:
|
||||
exclude: []
|
||||
include:
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
{{- if .Values.ui }}
|
||||
{{- $host := include "cozy-lib.ns-host-required" . }}
|
||||
{{- $endpoint := printf "s3.%s" $host }}
|
||||
{{- range $name, $user := .Values.users }}
|
||||
@@ -37,3 +38,4 @@ spec:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
{{- end }}
|
||||
@@ -1,3 +1,4 @@
|
||||
{{- if .Values.ui }}
|
||||
{{- $host := include "cozy-lib.ns-host-required" . }}
|
||||
{{- $gateway := .Values._namespace.gateway | default "" }}
|
||||
{{- if $gateway }}
|
||||
@@ -18,3 +19,4 @@ spec:
|
||||
- name: {{ .Values.bucketName }}-ui
|
||||
port: 8080
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -1,3 +1,4 @@
|
||||
{{- if .Values.ui }}
|
||||
{{- $host := include "cozy-lib.ns-host-required" . }}
|
||||
{{- $ingress := .Values._namespace.ingress }}
|
||||
{{- $gateway := .Values._namespace.gateway | default "" }}
|
||||
@@ -44,3 +45,4 @@ spec:
|
||||
port:
|
||||
number: 8080
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -1,3 +1,4 @@
|
||||
{{- if .Values.ui }}
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
@@ -10,3 +11,4 @@ spec:
|
||||
port: 8080
|
||||
targetPort: 8080
|
||||
type: ClusterIP
|
||||
{{- end }}
|
||||
@@ -0,0 +1,67 @@
|
||||
suite: bucket UI can be switched off
|
||||
templates:
|
||||
- templates/deployment.yaml
|
||||
- templates/service.yaml
|
||||
- templates/ingress.yaml
|
||||
- templates/httproute.yaml
|
||||
|
||||
release:
|
||||
name: bucket
|
||||
namespace: tenant-root
|
||||
|
||||
set:
|
||||
_namespace:
|
||||
host: example.org
|
||||
ingress: tenant-root
|
||||
|
||||
tests:
|
||||
- it: renders the UI Deployment, Service and Ingress by default
|
||||
asserts:
|
||||
- template: templates/deployment.yaml
|
||||
hasDocuments:
|
||||
count: 1
|
||||
- template: templates/service.yaml
|
||||
hasDocuments:
|
||||
count: 1
|
||||
- template: templates/ingress.yaml
|
||||
hasDocuments:
|
||||
count: 1
|
||||
|
||||
- it: renders none of the UI objects behind an Ingress when ui is false
|
||||
set:
|
||||
ui: false
|
||||
asserts:
|
||||
- template: templates/deployment.yaml
|
||||
hasDocuments:
|
||||
count: 0
|
||||
- template: templates/service.yaml
|
||||
hasDocuments:
|
||||
count: 0
|
||||
- template: templates/ingress.yaml
|
||||
hasDocuments:
|
||||
count: 0
|
||||
|
||||
- it: renders no HTTPRoute behind a Gateway when ui is false
|
||||
set:
|
||||
ui: false
|
||||
_namespace:
|
||||
gateway: tenant-root
|
||||
asserts:
|
||||
- template: templates/httproute.yaml
|
||||
hasDocuments:
|
||||
count: 0
|
||||
|
||||
# The UI hostname is the only consumer of the tenant apex in this chart, so
|
||||
# a bucket without it must not trip the empty-apex guard.
|
||||
- it: does not require the tenant apex when ui is false
|
||||
set:
|
||||
ui: false
|
||||
_namespace:
|
||||
host: ""
|
||||
asserts:
|
||||
- template: templates/deployment.yaml
|
||||
hasDocuments:
|
||||
count: 0
|
||||
- template: templates/ingress.yaml
|
||||
hasDocuments:
|
||||
count: 0
|
||||
@@ -5,3 +5,4 @@ _namespace: {}
|
||||
|
||||
bucketName: "cozystack"
|
||||
users: {}
|
||||
ui: true
|
||||
Reference in new issue
Block a user