Compare commits

...
Sign in to create a new pull request.

18 commits

Author SHA1 Message Date
IvanHunters
89b543493a
fix(dashboard): handle ConfigMap adoption and add checksum rollout
Add pre-upgrade/pre-install hook that labels and annotates the
branding ConfigMap with Helm ownership metadata, allowing Helm to
adopt resources that were created outside of Helm.

Add checksum/config annotation to console pod template so that
branding changes trigger an automatic rolling restart, matching
the behavior of the previous dashboard chart.

Signed-off-by: IvanHunters <ivan.okhotnikov@aenix.io>
2026-04-30 01:26:30 +03:00
IvanHunters
d2dd687a07
fix(dashboard): quote config.json value in branding ConfigMap
toJson returns a string that must be quoted in YAML data fields,
otherwise Kubernetes API rejects the manifest as the value is parsed
as an object instead of a string.

Signed-off-by: IvanHunters <ivan.okhotnikov@aenix.io>
2026-04-30 01:10:05 +03:00
IvanHunters
b091073e87
chore(dashboard): bump cozystack-ui ref to dd1ff0b
Includes branding config fetch, backup/VNC fixes, and signoff cleanup.

Signed-off-by: IvanHunters <ivan.okhotnikov@aenix.io>
2026-04-30 01:06:07 +03:00
IvanHunters
da7258915f
feat(dashboard): serve branding config from ConfigMap via Kubernetes API
Add cozy-dashboard-console-config ConfigMap that renders _cluster.branding
values as JSON. The new console SPA fetches this ConfigMap at startup via
the Kubernetes API (/api/v1/namespaces/cozy-dashboard/configmaps/...) and
applies titleText, logoSvg, logoText without requiring nginx volume mounts
or pod restarts.

Add Role/RoleBinding granting system:authenticated read access to the
specific ConfigMap so the browser-side K8s API call succeeds.

Signed-off-by: IvanHunters <ivan.okhotnikov@aenix.io>
2026-04-30 01:05:23 +03:00
IvanHunters
fd259692b8
feat(dashboard): add runtime branding support via config.json
Introduce a ConfigMap that renders _cluster.branding values as JSON
and mounts it into the console container at /usr/share/nginx/html/config.json.
The new cozystack-ui reads this file at startup and applies titleText,
logoSvg, and logoText to the dashboard shell, restoring cluster-level
branding customization that was lost when the static SPA replaced the
old configmap-driven UI.

Signed-off-by: IvanHunters <ivan.okhotnikov@aenix.io>
2026-04-30 00:49:10 +03:00
IvanHunters
caaf4f90d4
fix(dashboard): restrict RBAC to cluster-scoped resources and cleanup naming
Remove namespace-scoped resources (tenantsecrets, tenantnamespaces,
tenantmodules, virtualmachineinstances, virtualmachineinstances/vnc) from
the cozystack-dashboard-readonly ClusterRole bound to system:authenticated.
These resources must be accessed via per-namespace RoleBindings created by
the tenant operator, not through a cluster-wide grant to all authenticated
users.

Only truly cluster-scoped, public-by-design resources remain in the
ClusterRole: applicationdefinitions, storageclasses, backupclasses,
and dashboard.cozystack.io customization resources.

Also rename the leftover incloud-web-web-user-edit ClusterRoleBinding to
cozystack-dashboard-cluster-admin to match the new naming convention, and
declare Makefile targets as .PHONY.

Signed-off-by: IvanHunters <ivan.okhotnikov@aenix.io>
2026-04-30 00:37:28 +03:00
IvanHunters
e8fbd4e8cc
fix(dashboard): drop arm64 platform to fix CI build
Default docker driver does not support multi-platform builds.
All other packages in make build use linux/amd64 only.

Signed-off-by: IvanHunters <ivan.okhotnikov@aenix.io>
2026-04-29 23:56:09 +03:00
IvanHunters
d7756866eb
fix(dashboard): update console to latest cozystack-ui commit
Signed-off-by: IvanHunters <ivan.okhotnikov@aenix.io>
2026-04-29 23:47:47 +03:00
IvanHunters
5445e3f213
fix(dashboard): use correct APP_VERSION build-arg name for console image
Containerfile expects ARG APP_VERSION, not COZYSTACK_VERSION

Signed-off-by: IvanHunters <ivan.okhotnikov@aenix.io>
2026-04-29 23:46:45 +03:00
IvanHunters
becf8d7572
fix(dashboard): complete migration to cozy-dashboard naming and fix RBAC
- Rename ClusterRoleBinding and update ServiceAccount references
- Update FlowSchema to use new cozy-dashboard-console service account
- Add core.cozystack.io permissions for tenant resources

Signed-off-by: IvanHunters <ivan.okhotnikov@aenix.io>
2026-04-29 23:28:53 +03:00
IvanHunters
41b355163d
fix(dashboard): pin console to specific commit and pass version to build
- Pin CONSOLE_REF to a specific commit hash for reproducible builds
- Fix git clone to support fetching by commit hash (not branch)
- Pass COZYSTACK_VERSION as build arg for version display in UI

Signed-off-by: IvanHunters <ivan.okhotnikov@aenix.io>
2026-04-29 23:28:48 +03:00
IvanHunters
574dabeb25 fix(dashboard): add VNC WebSocket support in console image build
- Add --file flag to specify Containerfile path in docker buildx
- Build console image from cozystack-ui feat/ui-overhaul branch
- Update console image with VNC fix (includes /k8s proxy location)

New console image includes nginx /k8s location for VNC WebSocket
routing to KubeVirt VMI subresources.

Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2026-04-28 23:51:13 +03:00
IvanHunters
6f78c23881 feat(dashboard): add console image build from cozystack-ui repository
Add Makefile target to build console image from external repository:
- Clone cozystack-ui repository (configurable via CONSOLE_REPO/CONSOLE_REF)
- Build multi-arch image (amd64, arm64)
- Push to registry and update values.yaml with digest
- Clean up temporary directory after build

This enables automated console image builds as part of the dashboard
release process, similar to how token-proxy is built.

Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2026-04-28 23:40:42 +03:00
IvanHunters
8b037d3045 refactor(dashboard): migrate to new cozystack-ui console
Remove old openapi-ui implementation and adopt new React-based console:

**Removed:**
- images/openapi-ui/ - old PRO-Robotech based UI
- images/openapi-ui-k8s-bff/ - unused backend-for-frontend
- templates/nginx.yaml - separate nginx proxy (replaced by built-in nginx)
- templates/configmap.yaml - old UI configuration

**Changes:**
- Rename web → console throughout all manifests
- Rename incloud-web-* → cozy-dashboard-* for all resources
- Remove all environment variables (new UI requires no configuration)
- Update gatekeeper upstream to point directly to console service
- Simplify Makefile (only token-proxy image build remains)
- Update values.yaml: openapiUI → console

**Architecture changes:**
Before: gatekeeper → nginx → web (openapi-ui)
After: gatekeeper → console (React SPA with built-in nginx)

The new console includes nginx that proxies /api and /apis to K8s API,
eliminating the need for a separate nginx deployment. Authentication
flow remains unchanged - gatekeeper adds Authorization header which
is passed through to K8s API.

Breaking change: Resource names changed from incloud-web-* to
cozy-dashboard-*. Existing deployments will need migration.

Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2026-04-28 23:38:58 +03:00
IvanHunters
c7c4f724af fix(dashboard): add VNC access permissions and update UI image
- Add RBAC permissions for VNC console access to virtual machines
- Update cozystack-ui image to latest version with VNC fixes

Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2026-04-28 23:35:46 +03:00
IvanHunters
4de9c50e2f fix(dashboard): update UI image with VNC WebSocket fix
Update to new image digest with dynamic WebSocket URL fix for VNC connections.
VNC now uses window.location instead of hardcoded localhost:8001.

Image: 999669/cozystack-ui:latest@sha256:ea4e832c2...
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2026-04-28 03:26:35 +03:00
IvanHunters
ddcc1f2ad6 feat(dashboard): update UI image to amd64 and remove old UI build
- Update openapiUI image to amd64 build (sha256:9d8fc5c1...)
- Remove old openapi-ui and openapi-ui-k8s-bff build targets from Makefile
- Remove old UI Dockerfiles and related files
- Add RBAC permissions for cozystack.io/applicationdefinitions to fix 403 errors

The new cozystack-ui requires read access to applicationdefinitions API group
for marketplace and application catalog functionality.

Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2026-04-28 03:20:04 +03:00
IvanHunters
ed01319aa1 feat(dashboard): replace UI with new cozystack-ui (keeping BFF)
Replace old openapi-ui with new cozystack-ui that proxies API requests through BFF.

Changes:
- New UI image: 999669/cozystack-ui:latest@sha256:74e39ad4
- BFF container: kept unchanged for K8s API authentication
- New UI includes TypeScript fixes and improved backup pages
- nginx configured to proxy /api and /apis to localhost:64231 (BFF)

Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2026-04-28 03:18:25 +03:00
24 changed files with 173 additions and 713 deletions

1
packages/system/dashboard/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
.tmp-cozystack-ui

View file

@ -4,51 +4,34 @@ export NAMESPACE=cozy-$(NAME)
include ../../../hack/common-envs.mk
include ../../../hack/package.mk
update: update-crd update-dockerfiles
image: image-openapi-ui image-openapi-ui-k8s-bff image-token-proxy update-tenant-text
.PHONY: image image-console image-token-proxy
image: image-console image-token-proxy
update-dockerfiles:
@echo Update dockerfiles manually
CONSOLE_REPO ?= https://github.com/cozystack/cozystack-ui.git
CONSOLE_REF ?= dd1ff0bdbd5e6e2fb6614fd1d831c4cb5c8f8025
update-crd:
rm -rf crds
mkdir -p crds
wget -O- https://github.com/PRO-Robotech/helmfile-manifests/archive/refs/heads/main.tar.gz | tar -C crds -xzvf- helmfile-manifests-main/charts/incloud-main/incloud-web-1.0.0/incloud-web/templates --strip-components=6
rm -f crds/_helpers.tpl
sed -i '/{{/d' crds/*.yml crds/*.yaml
image-openapi-ui:
docker buildx build images/openapi-ui \
image-console:
rm -rf .tmp-cozystack-ui
git clone --no-checkout $(CONSOLE_REPO) .tmp-cozystack-ui
git -C .tmp-cozystack-ui fetch --depth 1 origin $(CONSOLE_REF)
git -C .tmp-cozystack-ui checkout FETCH_HEAD
docker buildx build .tmp-cozystack-ui \
--file .tmp-cozystack-ui/Containerfile \
--provenance false \
--builder=$(BUILDER) \
--platform=linux/amd64 \
--tag $(REGISTRY)/openapi-ui:$(call settag,$(TAG)) \
--cache-from type=registry,ref=$(REGISTRY)/openapi-ui:latest \
--tag $(REGISTRY)/cozystack-ui:$(call settag,$(TAG)) \
--cache-from type=registry,ref=$(REGISTRY)/cozystack-ui:latest \
--cache-to type=inline \
--metadata-file images/openapi-ui.json \
--metadata-file images/console.json \
--build-arg APP_VERSION=$(COZYSTACK_VERSION) \
--push=$(PUSH) \
--label "org.opencontainers.image.source=https://github.com/cozystack/cozystack" \
--label "org.opencontainers.image.source=https://github.com/cozystack/cozystack-ui" \
--load=$(LOAD)
IMAGE="$(REGISTRY)/openapi-ui:$(call settag,$(TAG))@$$(yq e '."containerimage.digest"' images/openapi-ui.json -r)" \
yq -i '.openapiUI.image = strenv(IMAGE)' values.yaml
rm -f images/openapi-ui.json
image-openapi-ui-k8s-bff:
docker buildx build images/openapi-ui-k8s-bff \
--provenance false \
--builder=$(BUILDER) \
--platform=linux/amd64 \
--tag $(REGISTRY)/openapi-ui-k8s-bff:$(call settag,$(TAG)) \
--cache-from type=registry,ref=$(REGISTRY)/openapi-ui-k8s-bff:latest \
--cache-to type=inline \
--metadata-file images/openapi-ui-k8s-bff.json \
--push=$(PUSH) \
--label "org.opencontainers.image.source=https://github.com/cozystack/cozystack" \
--load=$(LOAD)
IMAGE="$(REGISTRY)/openapi-ui-k8s-bff:$(call settag,$(TAG))@$$(yq e '."containerimage.digest"' images/openapi-ui-k8s-bff.json -r)" \
yq -i '.openapiUIK8sBff.image = strenv(IMAGE)' values.yaml
rm -f images/openapi-ui-k8s-bff.json
IMAGE="$(REGISTRY)/cozystack-ui:$(call settag,$(TAG))@$$(yq e '."containerimage.digest"' images/console.json -r)" \
yq -i '.console.image = strenv(IMAGE)' values.yaml
rm -rf .tmp-cozystack-ui images/console.json
image-token-proxy:
docker buildx build images/token-proxy \
@ -65,6 +48,3 @@ image-token-proxy:
IMAGE="$(REGISTRY)/token-proxy:$(call settag,$(TAG))@$$(yq e '."containerimage.digest"' images/token-proxy.json -r)" \
yq -i '.tokenProxy.image = strenv(IMAGE)' values.yaml
rm -f images/token-proxy.json
update-tenant-text:
sed -i 's|\($$tenantText := "\)[^"]\+|\1$(TAG)|' templates/configmap.yaml

View file

@ -1,22 +0,0 @@
# imported from https://github.com/PRO-Robotech/openapi-ui-k8s-bff
ARG NODE_VERSION=20.18.1
FROM node:${NODE_VERSION}-alpine AS builder
WORKDIR /src
# release/1.4.0
ARG COMMIT_REF=92e4b618eb9ad17b19827b5a2b7ceab33e8cf534
RUN wget -O- https://github.com/PRO-Robotech/openapi-ui-k8s-bff/archive/${COMMIT_REF}.tar.gz | tar xzf - --strip-components=1
ENV PATH=/src/node_modules/.bin:$PATH
RUN npm install
RUN npm run build
FROM node:${NODE_VERSION}-alpine
WORKDIR /app
COPY --from=builder /src/package*.json /app/
COPY --from=builder /src/node_modules /app/node_modules
COPY --from=builder /src/src/swagger/swagger-output.json /app/dist/swagger/swagger-output.json
COPY --from=builder /src/dist /app/dist
EXPOSE 8080
USER 1001
CMD [ "node", "/app/dist/index.js"]

View file

@ -1,69 +0,0 @@
ARG NODE_VERSION=20.18.1
# openapi-k8s-toolkit
# imported from https://github.com/PRO-Robotech/openapi-k8s-toolkit
FROM node:${NODE_VERSION}-alpine AS openapi-k8s-toolkit-builder
RUN apk add git
WORKDIR /src
# release/1.4.0
ARG COMMIT=d6b9e4ad0d1eb9d3730f7f0c664792c8dda3214d
RUN wget -O- https://github.com/PRO-Robotech/openapi-k8s-toolkit/archive/${COMMIT}.tar.gz | tar -xzvf- --strip-components=1
COPY openapi-k8s-toolkit/patches /patches
RUN git apply /patches/*.diff
RUN npm install
RUN npm install --build-from-source @swc/core
RUN npm run build
# openapi-ui
# imported from https://github.com/PRO-Robotech/openapi-ui
FROM node:${NODE_VERSION}-alpine AS builder
#RUN apk add git
WORKDIR /src
# release/1.4.0
ARG COMMIT_REF=6addca6939264ef2e39801baa88c1460cc1aa53e
RUN wget -O- https://github.com/PRO-Robotech/openapi-ui/archive/${COMMIT_REF}.tar.gz | tar xzf - --strip-components=1
#COPY openapi-ui/patches /patches
#RUN git apply /patches/*.diff
ENV PATH=/src/node_modules/.bin:$PATH
RUN npm install
# add patched openapi-k8s-toolkit
RUN rm -rf node_modules/@prorobotech/openapi-k8s-toolkit/dist
COPY --from=openapi-k8s-toolkit-builder /src/dist node_modules/@prorobotech/openapi-k8s-toolkit/dist
RUN npm run build
FROM node:${NODE_VERSION}-alpine AS builder2
WORKDIR /src
ENV PATH=/src/node_modules/.bin:$PATH
COPY --from=builder /src/server/package.json ./
COPY --from=builder /src/server/package-lock.json ./
RUN npm install
COPY --from=builder /src/server server
COPY --from=builder /src/tsconfig.server.json ./
COPY --from=builder /src/build /src/build
RUN npm run server:build
FROM node:${NODE_VERSION}-alpine
WORKDIR /app
COPY --from=builder2 /src/node_modules /app/node_modules
COPY --from=builder2 /src/build /app/build
EXPOSE 8080
RUN sed -i -e 's|OpenAPI UI|Cozystack|g' build/index.html
# Fix Factory component: return null while loading instead of showing "Factory Not Found" 404
RUN APP_JS=$(find build -name "App-react.js" -type f | head -1) && \
if [ -n "$APP_JS" ]; then \
sed -i 's|const { data: factoryData } = useK8sSmartResource({|const { data: factoryData, isLoading: factoryIsLoading } = useK8sSmartResource({|' "$APP_JS" && \
sed -i '/Factory Not Found/s/return /return factoryIsLoading ? null : /' "$APP_JS" && \
echo "Factory loading patch applied to $APP_JS"; \
fi
USER 1001
CMD ["node", "/app/build/index.js"]

View file

@ -1,17 +0,0 @@
diff --git a/src/components/molecules/EnrichedTable/organisms/EnrichedTableProvider/utils.ts b/src/components/molecules/EnrichedTable/organisms/EnrichedTableProvider/utils.ts
--- a/src/components/molecules/EnrichedTable/organisms/EnrichedTableProvider/utils.ts
+++ b/src/components/molecules/EnrichedTable/organisms/EnrichedTableProvider/utils.ts
@@ -185,6 +185,11 @@
return `['${escaped}']`
})
}
- const jpQueryResult = jp.query(el, `$${resolvedJsonPath}`)
- fieldValue = Array.isArray(jpQueryResult) && jpQueryResult.length === 1 ? jpQueryResult[0] : jpQueryResult
+ if (/_flatMap[^\]]+_Key/.test(resolvedJsonPath)) {
+ // Placeholder was not resolved (row not yet expanded or key missing) — skip query
+ fieldValue = null
+ } else {
+ const jpQueryResult = jp.query(el, `$${resolvedJsonPath}`)
+ fieldValue = Array.isArray(jpQueryResult) && jpQueryResult.length === 1 ? jpQueryResult[0] : jpQueryResult
+ }
}

View file

@ -1,37 +0,0 @@
diff --git a/src/localTypes/formExtensions.ts b/src/localTypes/formExtensions.ts
--- a/src/localTypes/formExtensions.ts
+++ b/src/localTypes/formExtensions.ts
@@ -59,2 +59,4 @@
relatedValuePath?: string
+ allowEmpty?: boolean
+ persistType?: 'str' | 'number' | 'arr' | 'obj'
}
diff --git a/src/components/molecules/BlackholeForm/molecules/FormListInput/FormListInput.tsx b/src/components/molecules/BlackholeForm/molecules/FormListInput/FormListInput.tsx
--- a/src/components/molecules/BlackholeForm/molecules/FormListInput/FormListInput.tsx
+++ b/src/components/molecules/BlackholeForm/molecules/FormListInput/FormListInput.tsx
@@ -149,3 +149,10 @@
}, [relatedPath, form, arrName, fixedName, relatedFieldValue, onValuesChangeCallBack, isTouchedPeristed])
+ // When allowEmpty is set, auto-persist the field so the BFF preserves empty values
+ useEffect(() => {
+ if (customProps.allowEmpty) {
+ persistedControls.onPersistMark(persistName || name, customProps.persistType ?? 'str')
+ }
+ }, [customProps.allowEmpty, customProps.persistType, persistedControls, persistName, name])
+
const uri = prepareTemplate({
@@ -267,5 +274,14 @@
validateTrigger="onBlur"
hasFeedback={designNewLayout ? { icons: feedbackIcons } : true}
style={{ flex: 1 }}
+ normalize={(value: unknown) => {
+ if (customProps.allowEmpty && (value === undefined || value === null)) {
+ if (customProps.persistType === 'number') return 0
+ if (customProps.persistType === 'arr') return []
+ if (customProps.persistType === 'obj') return {}
+ return ''
+ }
+ return value
+ }}
>
<Select

View file

@ -1,29 +0,0 @@
diff --git a/src/components/organisms/DynamicComponents/molecules/SecretBase64Plain/SecretBase64Plain.tsx b/src/components/organisms/DynamicComponents/molecules/SecretBase64Plain/SecretBase64Plain.tsx
--- a/src/components/organisms/DynamicComponents/molecules/SecretBase64Plain/SecretBase64Plain.tsx
+++ b/src/components/organisms/DynamicComponents/molecules/SecretBase64Plain/SecretBase64Plain.tsx
@@ -145,6 +145,12 @@
<Styled.DisabledInput
$hidden={effectiveHidden}
onClick={e => handleInputClick(e, effectiveHidden, value)}
+ onCopy={e => {
+ if (!effectiveHidden) {
+ e.preventDefault()
+ e.clipboardData?.setData('text/plain', value)
+ }
+ }}
value={shownValue}
readOnly
/>
@@ -161,6 +167,12 @@
<Styled.DisabledInput
$hidden={effectiveHidden}
onClick={e => handleInputClick(e, effectiveHidden, value)}
+ onCopy={e => {
+ if (!effectiveHidden) {
+ e.preventDefault()
+ e.clipboardData?.setData('text/plain', value)
+ }
+ }}
value={shownValue}
readOnly
/>

View file

@ -1,50 +0,0 @@
diff --git a/src/components/molecules/EnrichedTable/organisms/EnrichedTable/utils.tsx b/src/components/molecules/EnrichedTable/organisms/EnrichedTable/utils.tsx
index 8bcef4d..2551e92 100644
--- a/src/components/molecules/EnrichedTable/organisms/EnrichedTable/utils.tsx
+++ b/src/components/molecules/EnrichedTable/organisms/EnrichedTable/utils.tsx
@@ -22,6 +22,15 @@ import { TableFactory } from '../../molecules'
import { ShortenedTextWithTooltip, FilterDropdown, TrimmedTags, TextAlignContainer, TinyButton } from './atoms'
import { TInternalDataForControls } from './types'
+const getPluralForm = (singular: string): string => {
+ // If already ends with 's', add 'es'
+ if (singular.endsWith('s')) {
+ return `${singular}es`
+ }
+ // Otherwise just add 's'
+ return `${singular}s`
+}
+
export const getCellRender = ({
value,
record,
@@ -255,7 +264,7 @@ export const getEnrichedColumnsWithControls = ({
key: 'controls',
className: 'controls',
width: 60,
- render: (value: TInternalDataForControls) => {
+ render: (value: TInternalDataForControls, record: unknown) => {
return (
// <TextAlignContainer $align="right" className="hideable">
<TextAlignContainer $align="center">
@@ -279,10 +288,19 @@ export const getEnrichedColumnsWithControls = ({
domEvent.stopPropagation()
domEvent.preventDefault()
if (key === 'edit') {
+ // Special case: redirect tenantmodules from core.cozystack.io to apps.cozystack.io with plural form
+ let apiGroupAndVersion = value.apiGroupAndVersion
+ let plural = value.plural
+ if (apiGroupAndVersion?.startsWith('core.cozystack.io/') && plural === 'tenantmodules') {
+ const appsApiVersion = apiGroupAndVersion.replace('core.cozystack.io/', 'apps.cozystack.io/')
+ const pluralName = getPluralForm(value.name)
+ apiGroupAndVersion = appsApiVersion
+ plural = pluralName
+ }
navigate(
`${baseprefix}/${value.cluster}${value.namespace ? `/${value.namespace}` : ''}${
value.syntheticProject ? `/${value.syntheticProject}` : ''
- }/${value.pathPrefix}/${value.apiGroupAndVersion}/${value.plural}/${value.name}?backlink=${
+ }/${value.pathPrefix}/${apiGroupAndVersion}/${plural}/${value.name}?backlink=${
value.backlink
}`,
)

View file

@ -0,0 +1,82 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: cozy-dashboard-adopt
namespace: cozy-dashboard
annotations:
"helm.sh/hook": pre-upgrade,pre-install
"helm.sh/hook-weight": "-10"
"helm.sh/hook-delete-policy": hook-succeeded,hook-failed
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: cozy-dashboard-adopt
namespace: cozy-dashboard
annotations:
"helm.sh/hook": pre-upgrade,pre-install
"helm.sh/hook-weight": "-10"
"helm.sh/hook-delete-policy": hook-succeeded,hook-failed
rules:
- apiGroups: [""]
resources: ["configmaps"]
resourceNames: ["cozy-dashboard-console-config"]
verbs: ["get", "patch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: cozy-dashboard-adopt
namespace: cozy-dashboard
annotations:
"helm.sh/hook": pre-upgrade,pre-install
"helm.sh/hook-weight": "-10"
"helm.sh/hook-delete-policy": hook-succeeded,hook-failed
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: cozy-dashboard-adopt
subjects:
- kind: ServiceAccount
name: cozy-dashboard-adopt
namespace: cozy-dashboard
---
apiVersion: batch/v1
kind: Job
metadata:
name: cozy-dashboard-adopt-configmap
namespace: cozy-dashboard
annotations:
"helm.sh/hook": pre-upgrade,pre-install
"helm.sh/hook-weight": "-5"
"helm.sh/hook-delete-policy": hook-succeeded,hook-failed
spec:
template:
spec:
serviceAccountName: cozy-dashboard-adopt
restartPolicy: Never
securityContext:
runAsNonRoot: true
runAsUser: 65534
seccompProfile:
type: RuntimeDefault
containers:
- name: adopt
image: rancher/kubectl:v1.29.10
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
command:
- /bin/sh
- -c
- |
kubectl annotate configmap cozy-dashboard-console-config \
--namespace cozy-dashboard \
meta.helm.sh/release-name={{ .Release.Name }} \
meta.helm.sh/release-namespace={{ .Release.Namespace }} \
--overwrite 2>/dev/null || true
kubectl label configmap cozy-dashboard-console-config \
--namespace cozy-dashboard \
app.kubernetes.io/managed-by=Helm \
--overwrite 2>/dev/null || true

View file

@ -1,12 +1,12 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: incloud-web-cluster-view
name: cozy-dashboard-cluster-view
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: view
subjects:
- kind: ServiceAccount
name: incloud-web-web
namespace: incloud-web
name: cozy-dashboard-console
namespace: {{ .Release.Namespace }}

View file

@ -2,7 +2,7 @@ apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
annotations: {}
name: incloud-web-web-user-edit
name: cozystack-dashboard-cluster-admin
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,28 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: cozy-dashboard-console-config-reader
namespace: cozy-dashboard
rules:
- apiGroups:
- ""
resources:
- configmaps
resourceNames:
- cozy-dashboard-console-config
verbs:
- get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: cozy-dashboard-console-config-reader
namespace: cozy-dashboard
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: cozy-dashboard-console-config-reader
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: system:authenticated

View file

@ -1,4 +1,4 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: incloud-web-nginx
name: cozy-dashboard-console

View file

@ -1,14 +1,14 @@
apiVersion: v1
kind: Service
metadata:
name: incloud-web-nginx
name: cozy-dashboard-console
spec:
ports:
- name: nginx-http
- name: http
port: 8080
protocol: TCP
targetPort: 8080
selector:
app.kubernetes.io/instance: incloud-web
app.kubernetes.io/name: nginx
app.kubernetes.io/instance: cozy-dashboard
app.kubernetes.io/name: console
type: ClusterIP

View file

@ -1,13 +1,13 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: incloud-web-nginx
name: cozy-dashboard-console
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/instance: incloud-web
app.kubernetes.io/name: nginx
app.kubernetes.io/instance: cozy-dashboard
app.kubernetes.io/name: console
strategy:
rollingUpdate:
maxSurge: 25%
@ -16,10 +16,10 @@ spec:
template:
metadata:
annotations:
checksum/config: {{ include (print $.Template.BasePath "/nginx-config.yaml") . | sha256sum }}
checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
labels:
app.kubernetes.io/instance: incloud-web
app.kubernetes.io/name: nginx
app.kubernetes.io/instance: cozy-dashboard
app.kubernetes.io/name: console
spec:
affinity:
podAntiAffinity:
@ -30,15 +30,15 @@ spec:
- key: app.kubernetes.io/name
operator: In
values:
- appSpec
- console
- key: app.kubernetes.io/instance
operator: In
values:
- incloud-web
- cozy-dashboard
topologyKey: kubernetes.io/hostname
weight: 100
containers:
- image: nginxinc/nginx-unprivileged:1.29-alpine
- image: {{ .Values.console.image | quote }}
imagePullPolicy: IfNotPresent
livenessProbe:
failureThreshold: 3
@ -50,7 +50,14 @@ spec:
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 2
name: nginx
startupProbe:
httpGet:
path: /healthcheck
port: 8080
scheme: HTTP
failureThreshold: 30
periodSeconds: 2
name: console
ports:
- containerPort: 8080
name: http
@ -78,23 +85,13 @@ spec:
type: RuntimeDefault
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /etc/nginx/conf.d/default.conf
name: configurationnginxfile
subPath: nginx-config
dnsPolicy: ClusterFirst
enableServiceLinks: false
hostIPC: false
hostNetwork: false
hostPID: false
preemptionPolicy: null
priorityClassName: system-cluster-critical
restartPolicy: Always
runtimeClassName: null
schedulerName: default-scheduler
serviceAccountName: incloud-web-nginx
serviceAccountName: cozy-dashboard-console
terminationGracePeriodSeconds: 30
volumes:
- configMap:
name: incloud-web-nginx-config
name: configurationnginxfile

View file

@ -10,7 +10,7 @@ spec:
- subjects:
- kind: ServiceAccount
serviceAccount:
name: incloud-web-web
name: cozy-dashboard-console
namespace: {{ .Release.Namespace }}
resourceRules:
- verbs: ["*"]

View file

@ -52,7 +52,7 @@ spec:
imagePullPolicy: IfNotPresent
args:
- --provider=oidc
- --upstream=http://incloud-web-nginx.{{ .Release.Namespace }}.svc:8080
- --upstream=http://cozy-dashboard-console.{{ .Release.Namespace }}.svc:8080
- --http-address=0.0.0.0:8000
- --redirect-url=https://dashboard.{{ $host }}/oauth2/callback
- --oidc-issuer-url=https://keycloak.{{ $host }}/realms/cozy
@ -97,7 +97,7 @@ spec:
image: {{ .Values.tokenProxy.image }}
imagePullPolicy: IfNotPresent
args:
- --upstream=http://incloud-web-nginx.{{ .Release.Namespace }}.svc:8080
- --upstream=http://cozy-dashboard-console.{{ .Release.Namespace }}.svc:8080
- --http-address=0.0.0.0:8000
- --cookie-refresh=1h
- --cookie-name=kc-access

View file

@ -1,97 +0,0 @@
{{- $host := index .Values._cluster "root-host" }}
apiVersion: v1
data:
nginx-config: |-
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 8080 default_server;
listen [::]:8080 default_server;
server_name _;
location ~ ^(/clusterlist|/api/clusters)$ {
add_header Content-Type application/json;
set $cluster_list '[{"api":"{{ $host }}","baseDomain":"{{ $host }}","description":"dashboard.{{ $host }}","externalDomain":"dashboard.{{ $host }}","name":"default","tenant":"dev"}]';
return 200 $cluster_list;
}
location /api/clusters/default {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $host;
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
rewrite /api/clusters/default/(.*) /$1 break;
proxy_pass http://incloud-web-nginx.{{ .Release.Namespace }}.svc:8080;
}
location /k8s/clusters/default/ {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $host;
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
rewrite /k8s/clusters/default/(.*) /$1 break;
proxy_pass https://kubernetes.default.svc:443;
}
location /k8s {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $host;
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
rewrite /k8s/(.*) /$1 break;
proxy_pass https://kubernetes.default.svc:443;
}
location /openapi-bff {
proxy_pass http://incloud-web-web.{{ .Release.Namespace }}.svc:64231;
}
location /openapi-bff-ws/ {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $host;
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
proxy_pass http://incloud-web-web.{{ .Release.Namespace }}.svc:64231;
}
location = /docs {
return 301 https://cozystack.io/docs/;
}
location = / {
return 301 https://dashboard.{{ $host }}/openapi-ui;
}
location / {
proxy_pass http://incloud-web-web.{{ .Release.Namespace }}.svc:8080;
}
location /healthcheck {
access_log off;
return 200 "Healthy\n";
}
}
kind: ConfigMap
metadata:
name: incloud-web-nginx-config

View file

@ -4,6 +4,14 @@ kind: ClusterRole
metadata:
name: cozystack-dashboard-readonly
rules:
- apiGroups:
- cozystack.io
resources:
- applicationdefinitions
verbs:
- get
- list
- watch
- apiGroups:
- dashboard.cozystack.io
resources:

View file

@ -1,4 +0,0 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: incloud-web-web

View file

@ -1,18 +0,0 @@
apiVersion: v1
kind: Service
metadata:
name: incloud-web-web
spec:
ports:
- name: bff-http
port: 64231
protocol: TCP
targetPort: 64231
- name: web-http
port: 8080
protocol: TCP
targetPort: 8080
selector:
app.kubernetes.io/instance: incloud-web
app.kubernetes.io/name: web
type: ClusterIP

View file

@ -1,274 +0,0 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: incloud-web-web
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/instance: incloud-web
app.kubernetes.io/name: web
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
annotations:
checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
labels:
app.kubernetes.io/instance: incloud-web
app.kubernetes.io/name: web
spec:
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- podAffinityTerm:
labelSelector:
matchExpressions:
- key: app.kubernetes.io/name
operator: In
values:
- appSpec
- key: app.kubernetes.io/instance
operator: In
values:
- incloud-web
topologyKey: kubernetes.io/hostname
weight: 100
containers:
- env:
- name: BASE_API_GROUP
value: dashboard.cozystack.io
- name: BASE_API_VERSION
value: v1alpha1
- name: BASE_NAMESPACE_FULL_PATH
value: "/apis/core.cozystack.io/v1alpha1/tenantnamespaces"
- name: BASE_NAVIGATION_RESOURCE_PLURAL
value: navigations
- name: BASE_NAVIGATION_RESOURCE_NAME
value: navigation
- name: BASE_FRONTEND_PREFIX
value: /openapi-ui
- name: BASE_FACTORY_NAMESPACED_API_KEY
value: base-factory-namespaced-api
- name: BASE_FACTORY_CLUSTERSCOPED_API_KEY
value: base-factory-clusterscoped-api
- name: BASE_FACTORY_NAMESPACED_BUILTIN_KEY
value: base-factory-namespaced-builtin
- name: BASE_FACTORY_CLUSTERSCOPED_BUILTIN_KEY
value: base-factory-clusterscoped-builtin
- name: BASE_NAMESPACE_FACTORY_KEY
value: base-factory-clusterscoped-builtin
- name: BASE_ALLOWED_AUTH_HEADERS
value: user-agent,accept,content-type,origin,referer,accept-encoding,cookie,authorization
- name: LOGGER
value: "true"
- name: LOGGER_WITH_HEADERS
value: "false"
- name: PORT
value: "64231"
image: {{ .Values.openapiUIK8sBff.image | quote }}
imagePullPolicy: IfNotPresent
livenessProbe:
failureThreshold: 3
httpGet:
path: /healthcheck
port: 64231
scheme: HTTP
initialDelaySeconds: 3
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 2
startupProbe:
httpGet:
path: /healthcheck
port: 64231
scheme: HTTP
failureThreshold: 30
periodSeconds: 2
name: bff
ports:
- containerPort: 64231
name: http-bff
protocol: TCP
resources:
limits:
cpu: 1
memory: 1Gi
requests:
cpu: 100m
ephemeral-storage: 50Mi
memory: 128Mi
securityContext:
allowPrivilegeEscalation: false
capabilities:
add: []
drop:
- ALL
privileged: false
readOnlyRootFilesystem: false
runAsGroup: 0
runAsNonRoot: true
runAsUser: 101
seccompProfile:
type: RuntimeDefault
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
- env:
- name: BASEPREFIX
value: /openapi-ui
- name: HIDE_INSIDE
value: "true"
- name: CUSTOMIZATION_API_GROUP
value: dashboard.cozystack.io
- name: CUSTOMIZATION_API_VERSION
value: v1alpha1
- name: CUSTOMIZATION_CFOMAPPING_RESOURCE_NAME
value: cfomapping
- name: CUSTOMIZATION_CFOMAPPING_RESOURCE_PLURAL
value: cfomappings
- name: CUSTOMIZATION_CFO_FALLBACK_ID
value: ""
- name: CUSTOMIZATION_NAVIGATION_RESOURCE_NAME
value: navigation
- name: CUSTOMIZATION_NAVIGATION_RESOURCE_PLURAL
value: navigations
- name: CUSTOMIZATION_SIDEBAR_FALLBACK_ID
value: ""
- name: CUSTOMIZATION_BREADCRUMBS_FALLBACK_ID
value: stock-project-api-table
- name: INSTANCES_API_GROUP
value: dashboard.cozystack.io
- name: INSTANCES_API_VERSION
value: v1alpha1
- name: INSTANCES_PLURAL
value: instances
- name: MARKETPLACE_KIND
value: MarketplacePanel
- name: MARKETPLACE_PLURAL
value: marketplacepanels
- name: NAVIGATE_FROM_CLUSTERLIST
value: /openapi-ui/~recordValue~/api-table/core.cozystack.io/v1alpha1/tenantnamespaces
- name: PROJECTS_API_GROUP
value: core.cozystack.io
- name: PROJECTS_API_VERSION
value: v1alpha1
- name: PROJECTS_PLURAL
value: tenantnamespaces
- name: CUSTOM_NAMESPACE_API_RESOURCE_API_GROUP
value: core.cozystack.io
- name: CUSTOM_NAMESPACE_API_RESOURCE_API_VERSION
value: v1alpha1
- name: CUSTOM_NAMESPACE_API_RESOURCE_PLURAL
value: tenantnamespaces
- name: BASE_FACTORY_NAMESPACED_API_KEY
value: base-factory-namespaced-api
- name: BASE_FACTORY_CLUSTERSCOPED_API_KEY
value: base-factory-clusterscoped-api
- name: BASE_FACTORY_NAMESPACED_BUILTIN_KEY
value: base-factory-namespaced-builtin
- name: BASE_FACTORY_CLUSTERSCOPED_BUILTIN_KEY
value: base-factory-clusterscoped-builtin
- name: BASE_NAMESPACE_FACTORY_KEY
value: base-factory-clusterscoped-builtin
- name: USE_NAMESPACE_NAV
value: "true"
- name: USE_NEW_NAVIGATION
value: "true"
- name: HIDE_NAVIGATION
value: "true"
- name: LOGIN_URL
value: "/oauth2/userinfo"
- name: LOGOUT_URL
value: "/oauth2/sign_out"
- name: LOGIN_USERNAME_FIELD
value: "preferredUsername"
- name: FOOTER_TEXT
valueFrom:
configMapKeyRef:
name: incloud-web-dashboard-config
key: FOOTER_TEXT
- name: TITLE_TEXT
valueFrom:
configMapKeyRef:
name: incloud-web-dashboard-config
key: TITLE_TEXT
- name: CUSTOM_TENANT_TEXT
valueFrom:
configMapKeyRef:
name: incloud-web-dashboard-config
key: CUSTOM_TENANT_TEXT
- name: LOGO_TEXT
valueFrom:
configMapKeyRef:
name: incloud-web-dashboard-config
key: LOGO_TEXT
- name: CUSTOM_LOGO_SVG
valueFrom:
configMapKeyRef:
name: incloud-web-dashboard-config
key: CUSTOM_LOGO_SVG
- name: ICON_SVG
valueFrom:
configMapKeyRef:
name: incloud-web-dashboard-config
key: ICON_SVG
image: {{ .Values.openapiUI.image | quote }}
imagePullPolicy: IfNotPresent
livenessProbe:
failureThreshold: 3
httpGet:
path: /healthcheck
port: 8080
scheme: HTTP
initialDelaySeconds: 3
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 2
startupProbe:
httpGet:
path: /healthcheck
port: 8080
scheme: HTTP
failureThreshold: 30
periodSeconds: 2
name: web
ports:
- containerPort: 8080
name: http
protocol: TCP
resources:
limits:
cpu: 200m
memory: 256Mi
requests:
cpu: 100m
ephemeral-storage: 50Mi
memory: 128Mi
securityContext:
allowPrivilegeEscalation: false
capabilities:
add: []
drop:
- ALL
privileged: false
readOnlyRootFilesystem: false
runAsGroup: 0
runAsNonRoot: true
runAsUser: 101
seccompProfile:
type: RuntimeDefault
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
dnsPolicy: ClusterFirst
enableServiceLinks: false
hostIPC: false
hostNetwork: false
hostPID: false
priorityClassName: system-cluster-critical
restartPolicy: Always
schedulerName: default-scheduler
serviceAccountName: incloud-web-web
terminationGracePeriodSeconds: 30

View file

@ -1,6 +1,4 @@
openapiUI:
image: ghcr.io/cozystack/cozystack/openapi-ui:v1.3.0@sha256:0fa79c373a62840a617ff1ca1b0e31931c13a6cf7b0bb0ff0dc191f047a465a3
openapiUIK8sBff:
image: ghcr.io/cozystack/cozystack/openapi-ui-k8s-bff:v1.3.0@sha256:1b3ea6d4c7dbbe6a8def3b2807fffdfab2ac4afc39d7a846e57dd491fa168f92
console:
image: 999669/cozystack-ui:latest@sha256:c5b0dcfa241603763150188150d56ab58fba1ea820bfdac92c601199057bf9a2
tokenProxy:
image: ghcr.io/cozystack/cozystack/token-proxy:v1.3.0@sha256:2e280991e07853ea48f97b0a42946afffa10d03d6a83d41099ed83e6ffc94fdc