Compare commits

...

4 Commits

Author SHA1 Message Date
Andrei Kvapil
725f70399f refactor: remove assets-server and switch to cozystack-operator
- Remove cozystack-assets-server and related manifests
- Move grafana dashboards to dedicated pod in grafana-operator
- Remove old installer (cozystack.yaml) and switch to cozystack-operator
- Remove cozystackOperator.enabled flag (operator is now always used)
- Remove obsolete platform templates (helmrepos, helmreleases, apps, namespaces)
- Update Makefile to build cozystack-operator and cozystack-packages
- Remove installer.sh script (replaced by operator)

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
2026-01-06 17:42:29 +01:00
Andrei Kvapil
49f7ac9192 refactor: move migrations to platform chart
- Move migrations from scripts/migrations/ to packages/core/platform/images/migrations/
- Create migration-hook.yaml template to run migrations as Helm pre-upgrade/pre-install hook
- Add Dockerfile and run-migrations.sh for migrations image
- Remove old cozystack-assets image directory
- Update platform Makefile to build migrations image instead of assets

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
2026-01-06 17:40:56 +01:00
Andrei Kvapil
ab8cc5ffd4 refactor: update CozystackResourceDefinition to use chartRef instead of chart
This commit replaces the `chart` field with `chartRef` in CozystackResourceDefinition
to support direct OCIRepository references instead of HelmRepository lookups.

Changes:
- Update API types to use ChartRef structure with Kind, Name, Namespace fields
- Modify HelmRelease reconciler to set spec.chartRef instead of spec.chart
- Update config and registry to use new ChartRef configuration
- Add backward compatibility in lineage mapper for both chartRef and legacy chart
- Update all CozystackResourceDefinition YAML files to use new format
- Regenerate CRDs and deepcopy functions

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
2026-01-06 17:39:08 +01:00
Andrei Kvapil
f5e6107e3a feat(api): show only hash in version column for applications and modules
Fix getVersion to parse "0.1.4+abcdef" format (with "+" separator)
instead of incorrectly looking for "sha256:" prefix.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
2026-01-06 17:38:17 +01:00
85 changed files with 1252 additions and 938 deletions

View File

@@ -1,4 +1,4 @@
.PHONY: manifests repos assets unit-tests helm-unit-tests
.PHONY: manifests assets unit-tests helm-unit-tests
build-deps:
@command -V find docker skopeo jq gh helm > /dev/null
@@ -26,21 +26,15 @@ build: build-deps
make -C packages/system/kamaji image
make -C packages/system/bucket image
make -C packages/system/objectstorage-controller image
make -C packages/system/grafana-operator image
make -C packages/core/testing image
make -C packages/core/talos image
make -C packages/core/platform image
make -C packages/core/installer image
make manifests
repos:
rm -rf _out
make -C packages/system repo
make -C packages/apps repo
make -C packages/extra repo
manifests:
mkdir -p _out/assets
(cd packages/core/installer/; helm template -n cozy-installer installer .) > _out/assets/cozystack-installer.yaml
(cd packages/core/installer/; helm template --namespace cozy-installer installer .) > _out/assets/cozystack-installer.yaml
assets:
make -C packages/core/talos assets

View File

@@ -17,6 +17,7 @@ limitations under the License.
package v1alpha1
import (
helmv2 "github.com/fluxcd/helm-controller/api/v2"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
@@ -61,24 +62,6 @@ type CozystackResourceDefinitionSpec struct {
Dashboard *CozystackResourceDefinitionDashboard `json:"dashboard,omitempty"`
}
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"`
@@ -91,9 +74,8 @@ type CozystackResourceDefinitionApplication struct {
}
type CozystackResourceDefinitionRelease struct {
// Helm chart configuration
// +optional
Chart CozystackResourceDefinitionChart `json:"chart,omitempty"`
// Reference to the chart source
ChartRef *helmv2.CrossNamespaceSourceReference `json:"chartRef"`
// Labels for the release
Labels map[string]string `json:"labels,omitempty"`
// Prefix for the release name

View File

@@ -21,6 +21,7 @@ limitations under the License.
package v1alpha1
import (
"github.com/fluxcd/helm-controller/api/v2"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -118,22 +119,6 @@ func (in *CozystackResourceDefinitionApplication) DeepCopy() *CozystackResourceD
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 *CozystackResourceDefinitionDashboard) DeepCopyInto(out *CozystackResourceDefinitionDashboard) {
*out = *in
@@ -205,7 +190,11 @@ func (in *CozystackResourceDefinitionList) DeepCopyObject() runtime.Object {
// 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.ChartRef != nil {
in, out := &in.ChartRef, &out.ChartRef
*out = new(v2.CrossNamespaceSourceReference)
**out = **in
}
if in.Labels != nil {
in, out := &in.Labels, &out.Labels
*out = make(map[string]string, len(*in))
@@ -622,21 +611,6 @@ 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 *Variant) DeepCopyInto(out *Variant) {
*out = *in

View File

@@ -1,29 +0,0 @@
package main
import (
"flag"
"log"
"net/http"
"path/filepath"
)
func main() {
addr := flag.String("address", ":8123", "Address to listen on")
dir := flag.String("dir", "/cozystack/assets", "Directory to serve files from")
flag.Parse()
absDir, err := filepath.Abs(*dir)
if err != nil {
log.Fatalf("Error getting absolute path for %s: %v", *dir, err)
}
fs := http.FileServer(http.Dir(absDir))
http.Handle("/", fs)
log.Printf("Server starting on %s, serving directory %s", *addr, absDir)
err = http.ListenAndServe(*addr, nil)
if err != nil {
log.Fatalf("Server failed to start: %v", err)
}
}

View File

@@ -73,7 +73,7 @@ func (r *CozystackResourceDefinitionHelmReconciler) updateHelmReleasesForCRD(ctx
labelSelector := client.MatchingLabels{
"apps.cozystack.io/application.kind": applicationKind,
"apps.cozystack.io/application.group": applicationGroup,
"cozystack.io/ui": "true",
"cozystack.io/ui": "true",
}
// List all HelmReleases with matching labels
@@ -130,55 +130,30 @@ func (r *CozystackResourceDefinitionHelmReconciler) updateHelmReleaseChart(ctx c
hrCopy := hr.DeepCopy()
updated := false
// Validate Chart configuration exists
if crd.Spec.Release.Chart.Name == "" {
logger.V(4).Info("Skipping HelmRelease chart update: Chart.Name is empty", "crd", crd.Name)
// Validate ChartRef configuration exists
if crd.Spec.Release.ChartRef == nil ||
crd.Spec.Release.ChartRef.Kind == "" ||
crd.Spec.Release.ChartRef.Name == "" ||
crd.Spec.Release.ChartRef.Namespace == "" {
logger.Error(fmt.Errorf("invalid ChartRef in CRD"), "Skipping HelmRelease chartRef update: ChartRef is nil or incomplete",
"crd", crd.Name)
return nil
}
// Validate SourceRef fields
if crd.Spec.Release.Chart.SourceRef.Kind == "" ||
crd.Spec.Release.Chart.SourceRef.Name == "" ||
crd.Spec.Release.Chart.SourceRef.Namespace == "" {
logger.Error(fmt.Errorf("invalid SourceRef in CRD"), "Skipping HelmRelease chart update: SourceRef fields are incomplete",
"crd", crd.Name,
"kind", crd.Spec.Release.Chart.SourceRef.Kind,
"name", crd.Spec.Release.Chart.SourceRef.Name,
"namespace", crd.Spec.Release.Chart.SourceRef.Namespace)
return nil
}
// Use ChartRef directly from CRD
expectedChartRef := crd.Spec.Release.ChartRef
// Get version and reconcileStrategy from CRD or use defaults
version := ">= 0.0.0-0"
reconcileStrategy := "Revision"
// TODO: Add Version and ReconcileStrategy fields to CozystackResourceDefinitionChart if needed
// Build expected SourceRef
expectedSourceRef := helmv2.CrossNamespaceObjectReference{
Kind: crd.Spec.Release.Chart.SourceRef.Kind,
Name: crd.Spec.Release.Chart.SourceRef.Name,
Namespace: crd.Spec.Release.Chart.SourceRef.Namespace,
}
if hrCopy.Spec.Chart == nil {
// Need to create Chart spec
hrCopy.Spec.Chart = &helmv2.HelmChartTemplate{
Spec: helmv2.HelmChartTemplateSpec{
Chart: crd.Spec.Release.Chart.Name,
Version: version,
ReconcileStrategy: reconcileStrategy,
SourceRef: expectedSourceRef,
},
}
// Check if chartRef needs to be updated
if hrCopy.Spec.ChartRef == nil {
hrCopy.Spec.ChartRef = expectedChartRef
// Clear the old chart field when switching to chartRef
hrCopy.Spec.Chart = nil
updated = true
} else if hrCopy.Spec.ChartRef.Kind != expectedChartRef.Kind ||
hrCopy.Spec.ChartRef.Name != expectedChartRef.Name ||
hrCopy.Spec.ChartRef.Namespace != expectedChartRef.Namespace {
hrCopy.Spec.ChartRef = expectedChartRef
updated = true
} else {
// Update existing Chart spec
if hrCopy.Spec.Chart.Spec.Chart != crd.Spec.Release.Chart.Name ||
hrCopy.Spec.Chart.Spec.SourceRef != expectedSourceRef {
hrCopy.Spec.Chart.Spec.Chart = crd.Spec.Release.Chart.Name
hrCopy.Spec.Chart.Spec.SourceRef = expectedSourceRef
updated = true
}
}
// Check and update valuesFrom configuration
@@ -190,7 +165,7 @@ func (r *CozystackResourceDefinitionHelmReconciler) updateHelmReleaseChart(ctx c
}
if updated {
logger.V(4).Info("Updating HelmRelease chart", "name", hr.Name, "namespace", hr.Namespace)
logger.V(4).Info("Updating HelmRelease chartRef", "name", hr.Name, "namespace", hr.Namespace)
if err := r.Update(ctx, hrCopy); err != nil {
return fmt.Errorf("failed to update HelmRelease: %w", err)
}
@@ -198,4 +173,3 @@ func (r *CozystackResourceDefinitionHelmReconciler) updateHelmReleaseChart(ctx c
return nil
}

View File

@@ -7,51 +7,42 @@ pre-checks:
../../../hack/pre-checks.sh
show:
cozyhr show -n $(NAMESPACE) $(NAME) --plain
cozyhr show --namespace $(NAMESPACE) $(NAME) --plain
apply:
cozyhr show -n $(NAMESPACE) $(NAME) --plain | kubectl apply -f-
cozyhr show --namespace $(NAMESPACE) $(NAME) --plain | kubectl apply --filename -
diff:
cozyhr show -n $(NAMESPACE) $(NAME) --plain | kubectl diff -f -
cozyhr show --namespace $(NAMESPACE) $(NAME) --plain | kubectl diff --filename -
image: pre-checks image-cozystack
image-cozystack:
docker buildx build -f images/cozystack/Dockerfile ../../.. \
--tag $(REGISTRY)/installer:$(call settag,$(TAG)) \
--cache-from type=registry,ref=$(REGISTRY)/installer:latest \
--cache-to type=inline \
--metadata-file images/installer.json \
$(BUILDX_ARGS)
IMAGE="$(REGISTRY)/installer:$(call settag,$(TAG))@$$(yq e '."containerimage.digest"' images/installer.json -o json -r)" \
yq -i '.cozystack.image = strenv(IMAGE)' values.yaml
rm -f images/installer.json
image: pre-checks image-operator image-packages
update-version:
TAG="$(call settag,$(TAG))" \
yq -i '.cozystackOperator.cozystackVersion = strenv(TAG)' values.yaml
yq --inplace '.cozystackOperator.cozystackVersion = strenv(TAG)' values.yaml
image-operator:
docker buildx build -f images/cozystack-operator/Dockerfile ../../.. \
--tag $(REGISTRY)/cozystack-operator:$(call settag,$(TAG)) \
--cache-from type=registry,ref=$(REGISTRY)/cozystack-operator:latest \
--cache-to type=inline \
--metadata-file images/cozystack-operator.json \
$(BUILDX_ARGS)
IMAGE="$(REGISTRY)/cozystack-operator:$(call settag,$(TAG))@$$(yq e '."containerimage.digest"' images/cozystack-operator.json -o json -r)" \
yq -i '.cozystackOperator.image = strenv(IMAGE)' values.yaml
docker buildx build --file images/cozystack-operator/Dockerfile ../../.. \
--tag $(REGISTRY)/cozystack-operator:$(call settag,$(TAG)) \
--cache-from type=registry,ref=$(REGISTRY)/cozystack-operator:latest \
--cache-to type=inline \
--metadata-file images/cozystack-operator.json \
$(BUILDX_ARGS)
IMAGE="$(REGISTRY)/cozystack-operator:$(call settag,$(TAG))@$$(yq --exit-status '.["containerimage.digest"]' images/cozystack-operator.json --output-format json --raw-output)" \
yq --inplace '.cozystackOperator.image = strenv(IMAGE)' values.yaml
rm -f images/cozystack-operator.json
image-packages: update-version
mkdir -p ../../../_out/assets images
flux push artifact \
oci://$(REGISTRY)/platform-packages:$(call settag,$(TAG)) \
--path=../../../packages \
--source=https://github.com/cozystack/cozystack \
--revision="$$(git describe --tags):$$(git rev-parse HEAD)" \
2>&1 | tee images/cozystack-packages.log
export REPO="oci://$(REGISTRY)/platform-packages"; \
export DIGEST=$$(awk -F@ '/artifact successfully pushed/ {print $$2}' images/cozystack-packages.log; rm -f images/cozystack-packages.log); \
test -n "$$DIGEST" && yq -i '.cozystackOperator.platformSource = (strenv(REPO) + "@" + strenv(DIGEST))' values.yaml
oci://$(REGISTRY)/cozystack-packages:$(call settag,$(TAG)) \
--path=../../../packages \
--source=https://github.com/cozystack/cozystack \
--revision="$$(git describe --tags):$$(git rev-parse HEAD)" \
2>&1 | tee images/cozystack-packages.log
REPO="oci://$(REGISTRY)/cozystack-packages" \
DIGEST=$$(awk --field-separator @ '/artifact successfully pushed/ {print $$2}' images/cozystack-packages.log) && \
rm -f images/cozystack-packages.log && \
test -n "$$DIGEST" && \
yq --inplace '.cozystackOperator.platformSourceUrl = strenv(REPO)' values.yaml && \
yq --inplace '.cozystackOperator.platformSourceRef = "digest=" + strenv(DIGEST)' values.yaml

View File

@@ -1,41 +0,0 @@
FROM golang:1.24-alpine AS k8s-await-election-builder
ARG K8S_AWAIT_ELECTION_GITREPO=https://github.com/LINBIT/k8s-await-election
ARG K8S_AWAIT_ELECTION_VERSION=0.4.1
# TARGETARCH is a docker special variable: https://docs.docker.com/engine/reference/builder/#automatic-platform-args-in-the-global-scope
ARG TARGETARCH
RUN apk add --no-cache git make
RUN git clone ${K8S_AWAIT_ELECTION_GITREPO} /usr/local/go/k8s-await-election/ \
&& cd /usr/local/go/k8s-await-election \
&& git reset --hard v${K8S_AWAIT_ELECTION_VERSION} \
&& make \
&& mv ./out/k8s-await-election-${TARGETARCH} /k8s-await-election
FROM golang:1.25-alpine AS builder
ARG TARGETOS
ARG TARGETARCH
RUN apk add --no-cache make git
RUN apk add helm --repository=https://dl-cdn.alpinelinux.org/alpine/edge/community
COPY . /src/
WORKDIR /src
RUN go mod download
FROM alpine:3.22
RUN wget -O- https://github.com/cozystack/cozyhr/raw/refs/heads/main/hack/install.sh | sh -s -- -v 1.5.0
RUN apk add --no-cache make kubectl helm coreutils git jq openssl
COPY --from=builder /src/scripts /cozystack/scripts
COPY --from=builder /src/packages/core /cozystack/packages/core
COPY --from=builder /src/packages/system /cozystack/packages/system
COPY --from=k8s-await-election-builder /k8s-await-election /usr/bin/k8s-await-election
WORKDIR /cozystack
ENTRYPOINT ["/usr/bin/k8s-await-election", "/cozystack/scripts/installer.sh" ]

View File

@@ -1,4 +1,3 @@
{{- if .Values.cozystackOperator.enabled }}
---
apiVersion: v1
kind: Namespace
@@ -121,4 +120,3 @@ spec:
valuesFiles:
- values.yaml
- values-isp-hosted.yaml
{{- end }}

View File

@@ -1,81 +0,0 @@
{{- if not .Values.cozystackOperator.enabled }}
---
apiVersion: v1
kind: Namespace
metadata:
name: cozy-system
labels:
cozystack.io/system: "true"
pod-security.kubernetes.io/enforce: privileged
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: cozystack
namespace: cozy-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: cozystack
subjects:
- kind: ServiceAccount
name: cozystack
namespace: cozy-system
roleRef:
kind: ClusterRole
name: cluster-admin
apiGroup: rbac.authorization.k8s.io
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: cozystack
namespace: cozy-system
spec:
replicas: 1
selector:
matchLabels:
app: cozystack
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 0
maxUnavailable: 1
template:
metadata:
labels:
app: cozystack
spec:
hostNetwork: true
serviceAccountName: cozystack
containers:
- name: cozystack
image: "{{ .Values.cozystack.image }}"
env:
- name: KUBERNETES_SERVICE_HOST
value: localhost
- name: INSTALL_FLUX
value: "true"
- name: KUBERNETES_SERVICE_PORT
value: "7445"
- name: K8S_AWAIT_ELECTION_ENABLED
value: "1"
- name: K8S_AWAIT_ELECTION_NAME
value: cozystack
- name: K8S_AWAIT_ELECTION_LOCK_NAME
value: cozystack
- name: K8S_AWAIT_ELECTION_LOCK_NAMESPACE
value: cozy-system
- name: K8S_AWAIT_ELECTION_IDENTITY
valueFrom:
fieldRef:
fieldPath: metadata.name
tolerations:
- key: "node.kubernetes.io/not-ready"
operator: "Exists"
effect: "NoSchedule"
- key: "node.cilium.io/agent-not-ready"
operator: "Exists"
effect: "NoSchedule"
{{- end }}

View File

@@ -1,8 +1,5 @@
cozystack:
image: ghcr.io/cozystack/cozystack/installer:v0.38.2@sha256:9ff92b655de6f9bea3cba4cd42dcffabd9aace6966dcfb1cc02dda2420ea4a15
cozystackOperator:
enabled: false
image: ghcr.io/cozystack/cozystack/cozystack-operator:latest@sha256:f7f6e0fd9e896b7bfa642d0bfa4378bc14e646bc5c2e86e2e09a82770ef33181
platformSourceUrl: 'oci://ghcr.io/cozystack/cozystack/platform-packages'
platformSourceUrl: 'oci://ghcr.io/cozystack/cozystack/cozystack-packages'
platformSourceRef: 'digest=sha256:0576491291b33936cdf770a5c5b5692add97339c1505fc67a92df9d69dfbfdf6'
cozystackVersion: latest

View File

@@ -4,31 +4,26 @@ NAMESPACE=cozy-system
include ../../../scripts/common-envs.mk
show:
cozyhr show -n $(NAMESPACE) $(NAME) --plain
cozyhr show --namespace $(NAMESPACE) $(NAME) --plain
apply:
cozyhr show -n $(NAMESPACE) $(NAME) --plain | kubectl apply -f-
kubectl delete helmreleases.helm.toolkit.fluxcd.io -l cozystack.io/marked-for-deletion=true -A
cozyhr show --namespace $(NAMESPACE) $(NAME) --plain | kubectl apply --filename -
kubectl delete helmreleases.helm.toolkit.fluxcd.io --selector cozystack.io/marked-for-deletion=true --all-namespaces
reconcile: apply
namespaces-show:
cozyhr show -n $(NAMESPACE) $(NAME) --plain -s templates/namespaces.yaml
namespaces-apply:
cozyhr show -n $(NAMESPACE) $(NAME) --plain -s templates/namespaces.yaml | kubectl apply -f-
diff:
cozyhr show -n $(NAMESPACE) $(NAME) --plain | kubectl diff -f-
cozyhr show --namespace $(NAMESPACE) $(NAME) --plain | kubectl diff --filename -
image: image-assets
image-assets:
docker buildx build -f images/cozystack-assets/Dockerfile ../../.. \
--tag $(REGISTRY)/cozystack-assets:$(call settag,$(TAG)) \
--cache-from type=registry,ref=$(REGISTRY)/cozystack-assets:latest \
image: image-migrations
image-migrations:
docker buildx build --file images/migrations/Dockerfile . \
--tag $(REGISTRY)/platform-migrations:$(call settag,$(TAG)) \
--cache-from type=registry,ref=$(REGISTRY)/platform-migrations:latest \
--cache-to type=inline \
--metadata-file images/cozystack-assets.json \
--metadata-file images/migrations.json \
$(BUILDX_ARGS)
IMAGE="$(REGISTRY)/cozystack-assets:$(call settag,$(TAG))@$$(yq e '."containerimage.digest"' images/cozystack-assets.json -o json -r)" \
yq -i '.assets.image = strenv(IMAGE)' values.yaml
rm -f images/cozystack-assets.json
IMAGE="$(REGISTRY)/platform-migrations:$(call settag,$(TAG))@$$(yq --exit-status '.["containerimage.digest"]' images/migrations.json --output-format json --raw-output)" \
yq --inplace '.migrations.image = strenv(IMAGE)' values.yaml
rm -f images/migrations.json

View File

@@ -0,0 +1,638 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.20.0
name: cozystackresourcedefinitions.cozystack.io
spec:
group: cozystack.io
names:
kind: CozystackResourceDefinition
listKind: CozystackResourceDefinitionList
plural: cozystackresourcedefinitions
singular: cozystackresourcedefinition
scope: Cluster
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
dashboard:
description: Dashboard configuration for this resource
properties:
category:
description: Category used to group resources in the UI (e.g.,
"Storage", "Networking")
type: string
description:
description: Short description shown in catalogs or headers (e.g.,
"S3 compatible storage")
type: string
icon:
description: Icon encoded as a string (e.g., inline SVG, base64,
or data URI)
type: string
keysOrder:
description: Order of keys in the YAML view
items:
items:
type: string
type: array
type: array
module:
description: Whether this resource is a module (tenant module)
type: boolean
name:
description: Hard-coded name used in the UI (e.g., "bucket")
type: string
plural:
description: Plural human-readable name (e.g., "Buckets")
type: string
singular:
description: Human-readable name shown in the UI (e.g., "Bucket")
type: string
singularResource:
description: Whether this resource is singular (not a collection)
in the UI
type: boolean
tabs:
description: Which tabs to show for this resource
items:
description: DashboardTab enumerates allowed UI tabs.
enum:
- workloads
- ingresses
- services
- secrets
- yaml
type: string
type: array
tags:
description: Free-form tags for search and filtering
items:
type: string
type: array
weight:
description: Order weight for sorting resources in the UI (lower
first)
type: integer
required:
- category
- plural
- singular
type: object
ingresses:
description: Ingress selectors
properties:
exclude:
description: |-
Exclude contains an array of resource selectors that target resources.
If a resource matches the selector in any of the elements in the array, it is
hidden from the user, regardless of the matches in the include array.
items:
description: "CozystackResourceDefinitionResourceSelector extends
metav1.LabelSelector with resourceNames support.\nA resource
matches this selector only if it satisfies ALL criteria:\n-
Label selector conditions (matchExpressions and matchLabels)\n-
AND has a name that matches one of the names in resourceNames
(if specified)\n\nThe resourceNames field supports Go templates
with the following variables available:\n- {{ .name }}: The
name of the managing application (from apps.cozystack.io/application.name)\n-
{{ .kind }}: The lowercased kind of the managing application
(from apps.cozystack.io/application.kind)\n- {{ .namespace
}}: The namespace of the resource being processed\n\nExample
YAML:\n\n\tsecrets:\n\t include:\n\t - matchExpressions:\n\t
\ - key: badlabel\n\t operator: DoesNotExist\n\t matchLabels:\n\t
\ goodlabel: goodvalue\n\t resourceNames:\n\t -
\"{{ .name }}-secret\"\n\t - \"{{ .kind }}-{{ .name }}-tls\"\n\t
\ - \"specificname\""
properties:
matchExpressions:
description: matchExpressions is a list of label selector
requirements. The requirements are ANDed.
items:
description: |-
A label selector requirement is a selector that contains values, a key, and an operator that
relates the key and values.
properties:
key:
description: key is the label key that the selector
applies to.
type: string
operator:
description: |-
operator represents a key's relationship to a set of values.
Valid operators are In, NotIn, Exists and DoesNotExist.
type: string
values:
description: |-
values is an array of string values. If the operator is In or NotIn,
the values array must be non-empty. If the operator is Exists or DoesNotExist,
the values array must be empty. This array is replaced during a strategic
merge patch.
items:
type: string
type: array
x-kubernetes-list-type: atomic
required:
- key
- operator
type: object
type: array
x-kubernetes-list-type: atomic
matchLabels:
additionalProperties:
type: string
description: |-
matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
map is equivalent to an element of matchExpressions, whose key field is "key", the
operator is "In", and the values array contains only "value". The requirements are ANDed.
type: object
resourceNames:
description: |-
ResourceNames is a list of resource names to match
If specified, the resource must have one of these exact names to match the selector
items:
type: string
type: array
type: object
x-kubernetes-map-type: atomic
type: array
include:
description: |-
Include contains an array of resource selectors that target resources.
If a resource matches the selector in any of the elements in the array, and
matches none of the selectors in the exclude array that resource is marked
as a tenant resource and is visible to users.
items:
description: "CozystackResourceDefinitionResourceSelector extends
metav1.LabelSelector with resourceNames support.\nA resource
matches this selector only if it satisfies ALL criteria:\n-
Label selector conditions (matchExpressions and matchLabels)\n-
AND has a name that matches one of the names in resourceNames
(if specified)\n\nThe resourceNames field supports Go templates
with the following variables available:\n- {{ .name }}: The
name of the managing application (from apps.cozystack.io/application.name)\n-
{{ .kind }}: The lowercased kind of the managing application
(from apps.cozystack.io/application.kind)\n- {{ .namespace
}}: The namespace of the resource being processed\n\nExample
YAML:\n\n\tsecrets:\n\t include:\n\t - matchExpressions:\n\t
\ - key: badlabel\n\t operator: DoesNotExist\n\t matchLabels:\n\t
\ goodlabel: goodvalue\n\t resourceNames:\n\t -
\"{{ .name }}-secret\"\n\t - \"{{ .kind }}-{{ .name }}-tls\"\n\t
\ - \"specificname\""
properties:
matchExpressions:
description: matchExpressions is a list of label selector
requirements. The requirements are ANDed.
items:
description: |-
A label selector requirement is a selector that contains values, a key, and an operator that
relates the key and values.
properties:
key:
description: key is the label key that the selector
applies to.
type: string
operator:
description: |-
operator represents a key's relationship to a set of values.
Valid operators are In, NotIn, Exists and DoesNotExist.
type: string
values:
description: |-
values is an array of string values. If the operator is In or NotIn,
the values array must be non-empty. If the operator is Exists or DoesNotExist,
the values array must be empty. This array is replaced during a strategic
merge patch.
items:
type: string
type: array
x-kubernetes-list-type: atomic
required:
- key
- operator
type: object
type: array
x-kubernetes-list-type: atomic
matchLabels:
additionalProperties:
type: string
description: |-
matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
map is equivalent to an element of matchExpressions, whose key field is "key", the
operator is "In", and the values array contains only "value". The requirements are ANDed.
type: object
resourceNames:
description: |-
ResourceNames is a list of resource names to match
If specified, the resource must have one of these exact names to match the selector
items:
type: string
type: array
type: object
x-kubernetes-map-type: atomic
type: array
type: object
release:
description: Release configuration
properties:
chartRef:
description: Reference to the chart source
properties:
apiVersion:
description: APIVersion of the referent.
type: string
kind:
description: Kind of the referent.
enum:
- OCIRepository
- HelmChart
- ExternalArtifact
type: string
name:
description: Name of the referent.
maxLength: 253
minLength: 1
type: string
namespace:
description: |-
Namespace of the referent, defaults to the namespace of the Kubernetes
resource object that contains the reference.
maxLength: 63
minLength: 1
type: string
required:
- kind
- name
type: object
labels:
additionalProperties:
type: string
description: Labels for the release
type: object
prefix:
description: Prefix for the release name
type: string
required:
- chartRef
- prefix
type: object
secrets:
description: Secret selectors
properties:
exclude:
description: |-
Exclude contains an array of resource selectors that target resources.
If a resource matches the selector in any of the elements in the array, it is
hidden from the user, regardless of the matches in the include array.
items:
description: "CozystackResourceDefinitionResourceSelector extends
metav1.LabelSelector with resourceNames support.\nA resource
matches this selector only if it satisfies ALL criteria:\n-
Label selector conditions (matchExpressions and matchLabels)\n-
AND has a name that matches one of the names in resourceNames
(if specified)\n\nThe resourceNames field supports Go templates
with the following variables available:\n- {{ .name }}: The
name of the managing application (from apps.cozystack.io/application.name)\n-
{{ .kind }}: The lowercased kind of the managing application
(from apps.cozystack.io/application.kind)\n- {{ .namespace
}}: The namespace of the resource being processed\n\nExample
YAML:\n\n\tsecrets:\n\t include:\n\t - matchExpressions:\n\t
\ - key: badlabel\n\t operator: DoesNotExist\n\t matchLabels:\n\t
\ goodlabel: goodvalue\n\t resourceNames:\n\t -
\"{{ .name }}-secret\"\n\t - \"{{ .kind }}-{{ .name }}-tls\"\n\t
\ - \"specificname\""
properties:
matchExpressions:
description: matchExpressions is a list of label selector
requirements. The requirements are ANDed.
items:
description: |-
A label selector requirement is a selector that contains values, a key, and an operator that
relates the key and values.
properties:
key:
description: key is the label key that the selector
applies to.
type: string
operator:
description: |-
operator represents a key's relationship to a set of values.
Valid operators are In, NotIn, Exists and DoesNotExist.
type: string
values:
description: |-
values is an array of string values. If the operator is In or NotIn,
the values array must be non-empty. If the operator is Exists or DoesNotExist,
the values array must be empty. This array is replaced during a strategic
merge patch.
items:
type: string
type: array
x-kubernetes-list-type: atomic
required:
- key
- operator
type: object
type: array
x-kubernetes-list-type: atomic
matchLabels:
additionalProperties:
type: string
description: |-
matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
map is equivalent to an element of matchExpressions, whose key field is "key", the
operator is "In", and the values array contains only "value". The requirements are ANDed.
type: object
resourceNames:
description: |-
ResourceNames is a list of resource names to match
If specified, the resource must have one of these exact names to match the selector
items:
type: string
type: array
type: object
x-kubernetes-map-type: atomic
type: array
include:
description: |-
Include contains an array of resource selectors that target resources.
If a resource matches the selector in any of the elements in the array, and
matches none of the selectors in the exclude array that resource is marked
as a tenant resource and is visible to users.
items:
description: "CozystackResourceDefinitionResourceSelector extends
metav1.LabelSelector with resourceNames support.\nA resource
matches this selector only if it satisfies ALL criteria:\n-
Label selector conditions (matchExpressions and matchLabels)\n-
AND has a name that matches one of the names in resourceNames
(if specified)\n\nThe resourceNames field supports Go templates
with the following variables available:\n- {{ .name }}: The
name of the managing application (from apps.cozystack.io/application.name)\n-
{{ .kind }}: The lowercased kind of the managing application
(from apps.cozystack.io/application.kind)\n- {{ .namespace
}}: The namespace of the resource being processed\n\nExample
YAML:\n\n\tsecrets:\n\t include:\n\t - matchExpressions:\n\t
\ - key: badlabel\n\t operator: DoesNotExist\n\t matchLabels:\n\t
\ goodlabel: goodvalue\n\t resourceNames:\n\t -
\"{{ .name }}-secret\"\n\t - \"{{ .kind }}-{{ .name }}-tls\"\n\t
\ - \"specificname\""
properties:
matchExpressions:
description: matchExpressions is a list of label selector
requirements. The requirements are ANDed.
items:
description: |-
A label selector requirement is a selector that contains values, a key, and an operator that
relates the key and values.
properties:
key:
description: key is the label key that the selector
applies to.
type: string
operator:
description: |-
operator represents a key's relationship to a set of values.
Valid operators are In, NotIn, Exists and DoesNotExist.
type: string
values:
description: |-
values is an array of string values. If the operator is In or NotIn,
the values array must be non-empty. If the operator is Exists or DoesNotExist,
the values array must be empty. This array is replaced during a strategic
merge patch.
items:
type: string
type: array
x-kubernetes-list-type: atomic
required:
- key
- operator
type: object
type: array
x-kubernetes-list-type: atomic
matchLabels:
additionalProperties:
type: string
description: |-
matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
map is equivalent to an element of matchExpressions, whose key field is "key", the
operator is "In", and the values array contains only "value". The requirements are ANDed.
type: object
resourceNames:
description: |-
ResourceNames is a list of resource names to match
If specified, the resource must have one of these exact names to match the selector
items:
type: string
type: array
type: object
x-kubernetes-map-type: atomic
type: array
type: object
services:
description: Service selectors
properties:
exclude:
description: |-
Exclude contains an array of resource selectors that target resources.
If a resource matches the selector in any of the elements in the array, it is
hidden from the user, regardless of the matches in the include array.
items:
description: "CozystackResourceDefinitionResourceSelector extends
metav1.LabelSelector with resourceNames support.\nA resource
matches this selector only if it satisfies ALL criteria:\n-
Label selector conditions (matchExpressions and matchLabels)\n-
AND has a name that matches one of the names in resourceNames
(if specified)\n\nThe resourceNames field supports Go templates
with the following variables available:\n- {{ .name }}: The
name of the managing application (from apps.cozystack.io/application.name)\n-
{{ .kind }}: The lowercased kind of the managing application
(from apps.cozystack.io/application.kind)\n- {{ .namespace
}}: The namespace of the resource being processed\n\nExample
YAML:\n\n\tsecrets:\n\t include:\n\t - matchExpressions:\n\t
\ - key: badlabel\n\t operator: DoesNotExist\n\t matchLabels:\n\t
\ goodlabel: goodvalue\n\t resourceNames:\n\t -
\"{{ .name }}-secret\"\n\t - \"{{ .kind }}-{{ .name }}-tls\"\n\t
\ - \"specificname\""
properties:
matchExpressions:
description: matchExpressions is a list of label selector
requirements. The requirements are ANDed.
items:
description: |-
A label selector requirement is a selector that contains values, a key, and an operator that
relates the key and values.
properties:
key:
description: key is the label key that the selector
applies to.
type: string
operator:
description: |-
operator represents a key's relationship to a set of values.
Valid operators are In, NotIn, Exists and DoesNotExist.
type: string
values:
description: |-
values is an array of string values. If the operator is In or NotIn,
the values array must be non-empty. If the operator is Exists or DoesNotExist,
the values array must be empty. This array is replaced during a strategic
merge patch.
items:
type: string
type: array
x-kubernetes-list-type: atomic
required:
- key
- operator
type: object
type: array
x-kubernetes-list-type: atomic
matchLabels:
additionalProperties:
type: string
description: |-
matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
map is equivalent to an element of matchExpressions, whose key field is "key", the
operator is "In", and the values array contains only "value". The requirements are ANDed.
type: object
resourceNames:
description: |-
ResourceNames is a list of resource names to match
If specified, the resource must have one of these exact names to match the selector
items:
type: string
type: array
type: object
x-kubernetes-map-type: atomic
type: array
include:
description: |-
Include contains an array of resource selectors that target resources.
If a resource matches the selector in any of the elements in the array, and
matches none of the selectors in the exclude array that resource is marked
as a tenant resource and is visible to users.
items:
description: "CozystackResourceDefinitionResourceSelector extends
metav1.LabelSelector with resourceNames support.\nA resource
matches this selector only if it satisfies ALL criteria:\n-
Label selector conditions (matchExpressions and matchLabels)\n-
AND has a name that matches one of the names in resourceNames
(if specified)\n\nThe resourceNames field supports Go templates
with the following variables available:\n- {{ .name }}: The
name of the managing application (from apps.cozystack.io/application.name)\n-
{{ .kind }}: The lowercased kind of the managing application
(from apps.cozystack.io/application.kind)\n- {{ .namespace
}}: The namespace of the resource being processed\n\nExample
YAML:\n\n\tsecrets:\n\t include:\n\t - matchExpressions:\n\t
\ - key: badlabel\n\t operator: DoesNotExist\n\t matchLabels:\n\t
\ goodlabel: goodvalue\n\t resourceNames:\n\t -
\"{{ .name }}-secret\"\n\t - \"{{ .kind }}-{{ .name }}-tls\"\n\t
\ - \"specificname\""
properties:
matchExpressions:
description: matchExpressions is a list of label selector
requirements. The requirements are ANDed.
items:
description: |-
A label selector requirement is a selector that contains values, a key, and an operator that
relates the key and values.
properties:
key:
description: key is the label key that the selector
applies to.
type: string
operator:
description: |-
operator represents a key's relationship to a set of values.
Valid operators are In, NotIn, Exists and DoesNotExist.
type: string
values:
description: |-
values is an array of string values. If the operator is In or NotIn,
the values array must be non-empty. If the operator is Exists or DoesNotExist,
the values array must be empty. This array is replaced during a strategic
merge patch.
items:
type: string
type: array
x-kubernetes-list-type: atomic
required:
- key
- operator
type: object
type: array
x-kubernetes-list-type: atomic
matchLabels:
additionalProperties:
type: string
description: |-
matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
map is equivalent to an element of matchExpressions, whose key field is "key", the
operator is "In", and the values array contains only "value". The requirements are ANDed.
type: object
resourceNames:
description: |-
ResourceNames is a list of resource names to match
If specified, the resource must have one of these exact names to match the selector
items:
type: string
type: array
type: object
x-kubernetes-map-type: atomic
type: array
type: object
required:
- application
- release
type: object
type: object
served: true
storage: true

View File

@@ -1,25 +0,0 @@
FROM golang:1.25-alpine AS builder
ARG TARGETOS
ARG TARGETARCH
RUN apk add --no-cache make git
RUN apk add helm --repository=https://dl-cdn.alpinelinux.org/alpine/edge/community
COPY . /src/
WORKDIR /src
RUN go mod download
RUN go build -o /cozystack-assets-server -ldflags '-extldflags "-static" -w -s' ./cmd/cozystack-assets-server
RUN make repos
FROM alpine:3.22
COPY --from=builder /src/_out/repos /cozystack/assets/repos
COPY --from=builder /cozystack-assets-server /usr/bin/cozystack-assets-server
COPY --from=builder /src/dashboards /cozystack/assets/dashboards
WORKDIR /cozystack
ENTRYPOINT ["/usr/bin/cozystack-assets-server"]

View File

@@ -0,0 +1,12 @@
FROM alpine:3.22
RUN wget -O- https://github.com/cozystack/cozyhr/raw/refs/heads/main/hack/install.sh | sh -s -- -v 1.5.0
RUN apk add --no-cache kubectl helm coreutils git jq ca-certificates bash curl
COPY migrations /migrations
COPY run-migrations.sh /usr/bin/run-migrations.sh
WORKDIR /migrations
ENTRYPOINT ["/usr/bin/run-migrations.sh"]

View File

@@ -0,0 +1,41 @@
#!/bin/sh
set -euo pipefail
NAMESPACE="${NAMESPACE:-cozy-system}"
CURRENT_VERSION="${CURRENT_VERSION:-0}"
TARGET_VERSION="${TARGET_VERSION:-0}"
echo "Starting migrations from version $CURRENT_VERSION to $TARGET_VERSION"
# Check if ConfigMap exists
if ! kubectl get configmap --namespace "$NAMESPACE" cozystack-version >/dev/null 2>&1; then
echo "ConfigMap cozystack-version does not exist, creating it with version $TARGET_VERSION"
kubectl create configmap --namespace "$NAMESPACE" cozystack-version \
--from-literal=version="$TARGET_VERSION" \
--dry-run=client --output yaml | kubectl apply --filename -
echo "ConfigMap created with version $TARGET_VERSION"
exit 0
fi
# If current version is already at target, nothing to do
if [ "$CURRENT_VERSION" -ge "$TARGET_VERSION" ]; then
echo "Current version $CURRENT_VERSION is already at or above target version $TARGET_VERSION"
exit 0
fi
# Run migrations sequentially from current version to target version
for i in $(seq $((CURRENT_VERSION + 1)) $TARGET_VERSION); do
if [ -f "/migrations/$i" ]; then
echo "Running migration $i"
chmod +x /migrations/$i
/migrations/$i || {
echo "Migration $i failed"
exit 1
}
echo "Migration $i completed successfully"
else
echo "Migration $i not found, skipping"
fi
done
echo "All migrations completed successfully"

View File

@@ -1,73 +0,0 @@
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: cozystack-assets
namespace: cozy-system
labels:
app: cozystack-assets
spec:
serviceName: cozystack-assets
replicas: 1
selector:
matchLabels:
app: cozystack-assets
template:
metadata:
labels:
app: cozystack-assets
spec:
hostNetwork: true
containers:
- name: assets-server
image: "{{ .Values.assets.image }}"
args:
- "-dir=/cozystack/assets"
- "-address=:8123"
ports:
- name: http
containerPort: 8123
hostPort: 8123
tolerations:
- operator: Exists
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: cozystack-assets-reader
namespace: cozy-system
rules:
- apiGroups: [""]
resources:
- pods/proxy
resourceNames:
- cozystack-assets-0
verbs:
- get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: cozystack-assets-reader
namespace: cozy-system
subjects:
- kind: User
name: cozystack-assets-reader
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: cozystack-assets-reader
apiGroup: rbac.authorization.k8s.io
---
apiVersion: v1
kind: Service
metadata:
name: cozystack-assets
namespace: cozy-system
spec:
ports:
- name: http
port: 80
targetPort: 8123
selector:
app: cozystack-assets
type: ClusterIP

View File

@@ -1,40 +0,0 @@
---
apiVersion: source.toolkit.fluxcd.io/v1
kind: HelmRepository
metadata:
name: cozystack-system
namespace: cozy-system
labels:
cozystack.io/repository: system
spec:
interval: 5m0s
url: https://{{ include "cozystack.kubernetesAPIEndpoint" . }}/api/v1/namespaces/cozy-system/pods/cozystack-assets-0/proxy/repos/system
certSecretRef:
name: cozystack-assets-tls
---
apiVersion: source.toolkit.fluxcd.io/v1
kind: HelmRepository
metadata:
name: cozystack-apps
namespace: cozy-public
labels:
cozystack.io/ui: "true"
cozystack.io/repository: apps
spec:
interval: 5m0s
url: https://{{ include "cozystack.kubernetesAPIEndpoint" . }}/api/v1/namespaces/cozy-system/pods/cozystack-assets-0/proxy/repos/apps
certSecretRef:
name: cozystack-assets-tls
---
apiVersion: source.toolkit.fluxcd.io/v1
kind: HelmRepository
metadata:
name: cozystack-extra
namespace: cozy-public
labels:
cozystack.io/repository: extra
spec:
interval: 5m0s
url: https://{{ include "cozystack.kubernetesAPIEndpoint" . }}/api/v1/namespaces/cozy-system/pods/cozystack-assets-0/proxy/repos/extra
certSecretRef:
name: cozystack-assets-tls

View File

@@ -0,0 +1,69 @@
{{- $shouldRunMigrationHook := false }}
{{- $currentVersion := 0 }}
{{- $targetVersion := .Values.migrations.targetVersion | int }}
{{- $configMap := lookup "v1" "ConfigMap" .Release.Namespace "cozystack-version" }}
{{- if $configMap }}
{{- $currentVersion = dig "data" "version" "0" $configMap | int }}
{{- if lt $currentVersion $targetVersion }}
{{- $shouldRunMigrationHook = true }}
{{- end }}
{{- else }}
{{- $shouldRunMigrationHook = true }}
{{- end }}
{{- if $shouldRunMigrationHook }}
---
apiVersion: batch/v1
kind: Job
metadata:
name: cozystack-migration-hook
annotations:
helm.sh/hook: pre-upgrade,pre-install
helm.sh/hook-weight: "1"
helm.sh/hook-delete-policy: before-hook-creation
spec:
backoffLimit: 3
template:
metadata:
labels:
policy.cozystack.io/allow-to-apiserver: "true"
spec:
serviceAccountName: cozystack-migration-hook
containers:
- name: migration
image: {{ .Values.migrations.image }}
env:
- name: NAMESPACE
value: {{ .Release.Namespace | quote }}
- name: CURRENT_VERSION
value: {{ $currentVersion | quote }}
- name: TARGET_VERSION
value: {{ $targetVersion | quote }}
restartPolicy: Never
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
annotations:
helm.sh/hook: pre-upgrade,pre-install
helm.sh/hook-weight: "1"
helm.sh/hook-delete-policy: hook-succeeded,before-hook-creation
name: cozystack-migration-hook
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: cozystack-migration-hook
namespace: {{ .Release.Namespace | quote }}
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: cozystack-migration-hook
annotations:
helm.sh/hook: pre-upgrade,pre-install
helm.sh/hook-weight: "1"
helm.sh/hook-delete-policy: hook-succeeded,before-hook-creation
{{- end }}

View File

@@ -1,6 +0,0 @@
{{/*
{{- range $path, $_ := .Files.Glob "sources/*.yaml" }}
---
{{ $.Files.Get $path }}
{{- end }}
*/}}

View File

@@ -1,2 +1,3 @@
assets:
image: ghcr.io/cozystack/cozystack/cozystack-assets:latest@sha256:19b166819d0205293c85d8351a3e038dc4c146b876a8e2ae21dce1d54f0b9e33
migrations:
image: ghcr.io/cozystack/cozystack/platform-migrations:latest
targetVersion: 22

View File

@@ -1,6 +1,6 @@
{{- range (split "\n" (.Files.Get "dashboards.list")) }}
{{- $parts := split "/" . }}
{{- if eq (len $parts) 2 }}
{{- if eq (len $parts) 2 }}
---
apiVersion: grafana.integreatly.org/v1beta1
kind: GrafanaDashboard
@@ -11,6 +11,6 @@ spec:
instanceSelector:
matchLabels:
dashboards: grafana
url: http://cozystack-assets.cozy-system.svc/dashboards/{{ . }}.json
url: http://grafana-dashboards.cozy-grafana-operator.svc/{{ . }}.json
{{- end }}
{{- end }}

View File

@@ -13,12 +13,10 @@ spec:
prefix: ""
labels:
cozystack.io/ui: "true"
chart:
name: bootbox
sourceRef:
kind: HelmRepository
name: cozystack-extra
namespace: cozy-public
chartRef:
kind: OCIRepository
name: bootbox-rd
namespace: cozy-system
dashboard:
category: Administration
singular: BootBox

View File

@@ -13,12 +13,10 @@ spec:
prefix: bucket-
labels:
cozystack.io/ui: "true"
chart:
name: bucket
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
chartRef:
kind: OCIRepository
name: bucket-rd
namespace: cozy-system
dashboard:
singular: Bucket
plural: Buckets

View File

@@ -13,12 +13,10 @@ spec:
prefix: clickhouse-
labels:
cozystack.io/ui: "true"
chart:
name: clickhouse
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
chartRef:
kind: OCIRepository
name: clickhouse-rd
namespace: cozy-system
dashboard:
category: PaaS
singular: ClickHouse

View File

@@ -135,29 +135,22 @@ spec:
If a resource matches the selector in any of the elements in the array, it is
hidden from the user, regardless of the matches in the include array.
items:
description: |-
CozystackResourceDefinitionResourceSelector extends metav1.LabelSelector with resourceNames support.
A resource matches this selector only if it satisfies ALL criteria:
- Label selector conditions (matchExpressions and matchLabels)
- AND has a name that matches one of the names in resourceNames (if specified)
The resourceNames field supports Go templates with the following variables available:
- {{ .name }}: The name of the managing application (from apps.cozystack.io/application.name)
- {{ .kind }}: The lowercased kind of the managing application (from apps.cozystack.io/application.kind)
- {{ .namespace }}: The namespace of the resource being processed
Example YAML:
secrets:
include:
- matchExpressions:
- key: badlabel
operator: DoesNotExist
matchLabels:
goodlabel: goodvalue
resourceNames:
- "{{ .name }}-secret"
- "{{ .kind }}-{{ .name }}-tls"
- "specificname"
description: "CozystackResourceDefinitionResourceSelector extends
metav1.LabelSelector with resourceNames support.\nA resource
matches this selector only if it satisfies ALL criteria:\n-
Label selector conditions (matchExpressions and matchLabels)\n-
AND has a name that matches one of the names in resourceNames
(if specified)\n\nThe resourceNames field supports Go templates
with the following variables available:\n- {{ .name }}: The
name of the managing application (from apps.cozystack.io/application.name)\n-
{{ .kind }}: The lowercased kind of the managing application
(from apps.cozystack.io/application.kind)\n- {{ .namespace
}}: The namespace of the resource being processed\n\nExample
YAML:\n\n\tsecrets:\n\t include:\n\t - matchExpressions:\n\t
\ - key: badlabel\n\t operator: DoesNotExist\n\t matchLabels:\n\t
\ goodlabel: goodvalue\n\t resourceNames:\n\t -
\"{{ .name }}-secret\"\n\t - \"{{ .kind }}-{{ .name }}-tls\"\n\t
\ - \"specificname\""
properties:
matchExpressions:
description: matchExpressions is a list of label selector
@@ -217,29 +210,22 @@ spec:
matches none of the selectors in the exclude array that resource is marked
as a tenant resource and is visible to users.
items:
description: |-
CozystackResourceDefinitionResourceSelector extends metav1.LabelSelector with resourceNames support.
A resource matches this selector only if it satisfies ALL criteria:
- Label selector conditions (matchExpressions and matchLabels)
- AND has a name that matches one of the names in resourceNames (if specified)
The resourceNames field supports Go templates with the following variables available:
- {{ .name }}: The name of the managing application (from apps.cozystack.io/application.name)
- {{ .kind }}: The lowercased kind of the managing application (from apps.cozystack.io/application.kind)
- {{ .namespace }}: The namespace of the resource being processed
Example YAML:
secrets:
include:
- matchExpressions:
- key: badlabel
operator: DoesNotExist
matchLabels:
goodlabel: goodvalue
resourceNames:
- "{{ .name }}-secret"
- "{{ .kind }}-{{ .name }}-tls"
- "specificname"
description: "CozystackResourceDefinitionResourceSelector extends
metav1.LabelSelector with resourceNames support.\nA resource
matches this selector only if it satisfies ALL criteria:\n-
Label selector conditions (matchExpressions and matchLabels)\n-
AND has a name that matches one of the names in resourceNames
(if specified)\n\nThe resourceNames field supports Go templates
with the following variables available:\n- {{ .name }}: The
name of the managing application (from apps.cozystack.io/application.name)\n-
{{ .kind }}: The lowercased kind of the managing application
(from apps.cozystack.io/application.kind)\n- {{ .namespace
}}: The namespace of the resource being processed\n\nExample
YAML:\n\n\tsecrets:\n\t include:\n\t - matchExpressions:\n\t
\ - key: badlabel\n\t operator: DoesNotExist\n\t matchLabels:\n\t
\ goodlabel: goodvalue\n\t resourceNames:\n\t -
\"{{ .name }}-secret\"\n\t - \"{{ .kind }}-{{ .name }}-tls\"\n\t
\ - \"specificname\""
properties:
matchExpressions:
description: matchExpressions is a list of label selector
@@ -296,34 +282,29 @@ spec:
release:
description: Release configuration
properties:
chart:
description: Helm chart configuration
chartRef:
description: Reference to the chart source
properties:
name:
description: Name of the Helm chart
kind:
default: OCIRepository
description: Kind of the source reference (e.g., OCIRepository,
GitRepository)
type: string
name:
description: Name of the source reference
type: string
namespace:
default: cozy-system
description: Namespace of the source reference
type: string
path:
description: Path within the source artifact where the chart
is located
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:
- kind
- name
- sourceRef
- namespace
type: object
labels:
additionalProperties:
@@ -334,7 +315,7 @@ spec:
description: Prefix for the release name
type: string
required:
- chart
- chartRef
- prefix
type: object
secrets:
@@ -346,29 +327,22 @@ spec:
If a resource matches the selector in any of the elements in the array, it is
hidden from the user, regardless of the matches in the include array.
items:
description: |-
CozystackResourceDefinitionResourceSelector extends metav1.LabelSelector with resourceNames support.
A resource matches this selector only if it satisfies ALL criteria:
- Label selector conditions (matchExpressions and matchLabels)
- AND has a name that matches one of the names in resourceNames (if specified)
The resourceNames field supports Go templates with the following variables available:
- {{ .name }}: The name of the managing application (from apps.cozystack.io/application.name)
- {{ .kind }}: The lowercased kind of the managing application (from apps.cozystack.io/application.kind)
- {{ .namespace }}: The namespace of the resource being processed
Example YAML:
secrets:
include:
- matchExpressions:
- key: badlabel
operator: DoesNotExist
matchLabels:
goodlabel: goodvalue
resourceNames:
- "{{ .name }}-secret"
- "{{ .kind }}-{{ .name }}-tls"
- "specificname"
description: "CozystackResourceDefinitionResourceSelector extends
metav1.LabelSelector with resourceNames support.\nA resource
matches this selector only if it satisfies ALL criteria:\n-
Label selector conditions (matchExpressions and matchLabels)\n-
AND has a name that matches one of the names in resourceNames
(if specified)\n\nThe resourceNames field supports Go templates
with the following variables available:\n- {{ .name }}: The
name of the managing application (from apps.cozystack.io/application.name)\n-
{{ .kind }}: The lowercased kind of the managing application
(from apps.cozystack.io/application.kind)\n- {{ .namespace
}}: The namespace of the resource being processed\n\nExample
YAML:\n\n\tsecrets:\n\t include:\n\t - matchExpressions:\n\t
\ - key: badlabel\n\t operator: DoesNotExist\n\t matchLabels:\n\t
\ goodlabel: goodvalue\n\t resourceNames:\n\t -
\"{{ .name }}-secret\"\n\t - \"{{ .kind }}-{{ .name }}-tls\"\n\t
\ - \"specificname\""
properties:
matchExpressions:
description: matchExpressions is a list of label selector
@@ -428,29 +402,22 @@ spec:
matches none of the selectors in the exclude array that resource is marked
as a tenant resource and is visible to users.
items:
description: |-
CozystackResourceDefinitionResourceSelector extends metav1.LabelSelector with resourceNames support.
A resource matches this selector only if it satisfies ALL criteria:
- Label selector conditions (matchExpressions and matchLabels)
- AND has a name that matches one of the names in resourceNames (if specified)
The resourceNames field supports Go templates with the following variables available:
- {{ .name }}: The name of the managing application (from apps.cozystack.io/application.name)
- {{ .kind }}: The lowercased kind of the managing application (from apps.cozystack.io/application.kind)
- {{ .namespace }}: The namespace of the resource being processed
Example YAML:
secrets:
include:
- matchExpressions:
- key: badlabel
operator: DoesNotExist
matchLabels:
goodlabel: goodvalue
resourceNames:
- "{{ .name }}-secret"
- "{{ .kind }}-{{ .name }}-tls"
- "specificname"
description: "CozystackResourceDefinitionResourceSelector extends
metav1.LabelSelector with resourceNames support.\nA resource
matches this selector only if it satisfies ALL criteria:\n-
Label selector conditions (matchExpressions and matchLabels)\n-
AND has a name that matches one of the names in resourceNames
(if specified)\n\nThe resourceNames field supports Go templates
with the following variables available:\n- {{ .name }}: The
name of the managing application (from apps.cozystack.io/application.name)\n-
{{ .kind }}: The lowercased kind of the managing application
(from apps.cozystack.io/application.kind)\n- {{ .namespace
}}: The namespace of the resource being processed\n\nExample
YAML:\n\n\tsecrets:\n\t include:\n\t - matchExpressions:\n\t
\ - key: badlabel\n\t operator: DoesNotExist\n\t matchLabels:\n\t
\ goodlabel: goodvalue\n\t resourceNames:\n\t -
\"{{ .name }}-secret\"\n\t - \"{{ .kind }}-{{ .name }}-tls\"\n\t
\ - \"specificname\""
properties:
matchExpressions:
description: matchExpressions is a list of label selector
@@ -513,29 +480,22 @@ spec:
If a resource matches the selector in any of the elements in the array, it is
hidden from the user, regardless of the matches in the include array.
items:
description: |-
CozystackResourceDefinitionResourceSelector extends metav1.LabelSelector with resourceNames support.
A resource matches this selector only if it satisfies ALL criteria:
- Label selector conditions (matchExpressions and matchLabels)
- AND has a name that matches one of the names in resourceNames (if specified)
The resourceNames field supports Go templates with the following variables available:
- {{ .name }}: The name of the managing application (from apps.cozystack.io/application.name)
- {{ .kind }}: The lowercased kind of the managing application (from apps.cozystack.io/application.kind)
- {{ .namespace }}: The namespace of the resource being processed
Example YAML:
secrets:
include:
- matchExpressions:
- key: badlabel
operator: DoesNotExist
matchLabels:
goodlabel: goodvalue
resourceNames:
- "{{ .name }}-secret"
- "{{ .kind }}-{{ .name }}-tls"
- "specificname"
description: "CozystackResourceDefinitionResourceSelector extends
metav1.LabelSelector with resourceNames support.\nA resource
matches this selector only if it satisfies ALL criteria:\n-
Label selector conditions (matchExpressions and matchLabels)\n-
AND has a name that matches one of the names in resourceNames
(if specified)\n\nThe resourceNames field supports Go templates
with the following variables available:\n- {{ .name }}: The
name of the managing application (from apps.cozystack.io/application.name)\n-
{{ .kind }}: The lowercased kind of the managing application
(from apps.cozystack.io/application.kind)\n- {{ .namespace
}}: The namespace of the resource being processed\n\nExample
YAML:\n\n\tsecrets:\n\t include:\n\t - matchExpressions:\n\t
\ - key: badlabel\n\t operator: DoesNotExist\n\t matchLabels:\n\t
\ goodlabel: goodvalue\n\t resourceNames:\n\t -
\"{{ .name }}-secret\"\n\t - \"{{ .kind }}-{{ .name }}-tls\"\n\t
\ - \"specificname\""
properties:
matchExpressions:
description: matchExpressions is a list of label selector
@@ -595,29 +555,22 @@ spec:
matches none of the selectors in the exclude array that resource is marked
as a tenant resource and is visible to users.
items:
description: |-
CozystackResourceDefinitionResourceSelector extends metav1.LabelSelector with resourceNames support.
A resource matches this selector only if it satisfies ALL criteria:
- Label selector conditions (matchExpressions and matchLabels)
- AND has a name that matches one of the names in resourceNames (if specified)
The resourceNames field supports Go templates with the following variables available:
- {{ .name }}: The name of the managing application (from apps.cozystack.io/application.name)
- {{ .kind }}: The lowercased kind of the managing application (from apps.cozystack.io/application.kind)
- {{ .namespace }}: The namespace of the resource being processed
Example YAML:
secrets:
include:
- matchExpressions:
- key: badlabel
operator: DoesNotExist
matchLabels:
goodlabel: goodvalue
resourceNames:
- "{{ .name }}-secret"
- "{{ .kind }}-{{ .name }}-tls"
- "specificname"
description: "CozystackResourceDefinitionResourceSelector extends
metav1.LabelSelector with resourceNames support.\nA resource
matches this selector only if it satisfies ALL criteria:\n-
Label selector conditions (matchExpressions and matchLabels)\n-
AND has a name that matches one of the names in resourceNames
(if specified)\n\nThe resourceNames field supports Go templates
with the following variables available:\n- {{ .name }}: The
name of the managing application (from apps.cozystack.io/application.name)\n-
{{ .kind }}: The lowercased kind of the managing application
(from apps.cozystack.io/application.kind)\n- {{ .namespace
}}: The namespace of the resource being processed\n\nExample
YAML:\n\n\tsecrets:\n\t include:\n\t - matchExpressions:\n\t
\ - key: badlabel\n\t operator: DoesNotExist\n\t matchLabels:\n\t
\ goodlabel: goodvalue\n\t resourceNames:\n\t -
\"{{ .name }}-secret\"\n\t - \"{{ .kind }}-{{ .name }}-tls\"\n\t
\ - \"specificname\""
properties:
matchExpressions:
description: matchExpressions is a list of label selector

View File

@@ -14,12 +14,10 @@ spec:
labels:
cozystack.io/ui: "true"
internal.cozystack.io/tenantmodule: "true"
chart:
name: etcd
sourceRef:
kind: HelmRepository
name: cozystack-extra
namespace: cozy-public
chartRef:
kind: OCIRepository
name: etcd-rd
namespace: cozy-system
dashboard:
category: Administration
singular: Etcd

View File

@@ -13,12 +13,10 @@ spec:
prefix: ferretdb-
labels:
cozystack.io/ui: "true"
chart:
name: ferretdb
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
chartRef:
kind: OCIRepository
name: ferretdb-rd
namespace: cozy-system
dashboard:
category: PaaS
singular: FerretDB

View File

@@ -13,12 +13,10 @@ spec:
prefix: foundationdb-
labels:
cozystack.io/ui: "true"
chart:
name: foundationdb
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
chartRef:
kind: OCIRepository
name: foundationdb-rd
namespace: cozy-system
dashboard:
category: PaaS
singular: FoundationDB

View File

@@ -1,6 +1,7 @@
export NAME=grafana-operator
export NAMESPACE=cozy-grafana-operator
include ../../../scripts/common-envs.mk
include ../../../scripts/package.mk
update:
@@ -8,3 +9,14 @@ update:
mkdir -p charts
curl -sSL https://github.com/grafana-operator/grafana-operator/archive/refs/heads/master.tar.gz | \
tar xzvf - --strip 3 -C charts grafana-operator-master/deploy/helm/grafana-operator
image:
docker buildx build --file images/grafana-dashboards/Dockerfile ../../.. \
--tag $(REGISTRY)/grafana-dashboards:$(call settag,$(TAG)) \
--cache-from type=registry,ref=$(REGISTRY)/grafana-dashboards:latest \
--cache-to type=inline \
--metadata-file images/grafana-dashboards.json \
$(BUILDX_ARGS)
echo "$(REGISTRY)/grafana-dashboards:$(call settag,$(TAG))@$$(yq --exit-status '.["containerimage.digest"]' images/grafana-dashboards.json --output-format json --raw-output)" \
> images/grafana-dashboards.tag
rm -f images/grafana-dashboards.json

View File

@@ -0,0 +1 @@
ghcr.io/cozystack/cozystack/grafana-dashboards:latest

View File

@@ -0,0 +1,11 @@
FROM alpine:3.22
RUN apk add --no-cache darkhttpd
COPY dashboards /var/www/dashboards
WORKDIR /var/www
EXPOSE 8080
CMD ["darkhttpd", "/var/www/dashboards", "--port", "8080", "--addr", "0.0.0.0"]

View File

@@ -0,0 +1,3 @@
# Exclude everything except dashboards directory
*
!dashboards/**

View File

@@ -0,0 +1,41 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: grafana-dashboards
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: grafana-dashboards
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/component: dashboards
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: grafana-dashboards
app.kubernetes.io/instance: {{ .Release.Name }}
template:
metadata:
labels:
app.kubernetes.io/name: grafana-dashboards
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/component: dashboards
spec:
containers:
- name: dashboards
image: {{ $.Files.Get "images/grafana-dashboards.tag" | trim }}
ports:
- containerPort: 8080
name: http
protocol: TCP
livenessProbe:
httpGet:
path: /
port: 8080
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
httpGet:
path: /
port: 8080
initialDelaySeconds: 5
periodSeconds: 5

View File

@@ -0,0 +1,19 @@
apiVersion: v1
kind: Service
metadata:
name: grafana-dashboards
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: grafana-dashboards
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/component: dashboards
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 8080
protocol: TCP
name: http
selector:
app.kubernetes.io/name: grafana-dashboards
app.kubernetes.io/instance: {{ .Release.Name }}

View File

@@ -13,12 +13,10 @@ spec:
prefix: http-cache-
labels:
cozystack.io/ui: "true"
chart:
name: http-cache
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
chartRef:
kind: OCIRepository
name: http-cache-rd
namespace: cozy-system
dashboard:
category: NaaS
singular: HTTP Cache

View File

@@ -14,12 +14,10 @@ spec:
labels:
cozystack.io/ui: "true"
internal.cozystack.io/tenantmodule: "true"
chart:
name: info
sourceRef:
kind: HelmRepository
name: cozystack-extra
namespace: cozy-public
chartRef:
kind: OCIRepository
name: info-rd
namespace: cozy-system
dashboard:
name: info
category: Administration

View File

@@ -14,12 +14,10 @@ spec:
labels:
cozystack.io/ui: "true"
internal.cozystack.io/tenantmodule: "true"
chart:
name: ingress
sourceRef:
kind: HelmRepository
name: cozystack-extra
namespace: cozy-public
chartRef:
kind: OCIRepository
name: ingress-rd
namespace: cozy-system
dashboard:
category: Administration
singular: Ingress

View File

@@ -13,12 +13,10 @@ spec:
prefix: kafka-
labels:
cozystack.io/ui: "true"
chart:
name: kafka
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
chartRef:
kind: OCIRepository
name: kafka-rd
namespace: cozy-system
dashboard:
category: PaaS
singular: Kafka

View File

@@ -13,12 +13,10 @@ spec:
prefix: kubernetes-
labels:
cozystack.io/ui: "true"
chart:
name: kubernetes
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
chartRef:
kind: OCIRepository
name: kubernetes-rd
namespace: cozy-system
dashboard:
category: IaaS
singular: Kubernetes

View File

@@ -14,12 +14,10 @@ spec:
labels:
cozystack.io/ui: "true"
internal.cozystack.io/tenantmodule: "true"
chart:
name: monitoring
sourceRef:
kind: HelmRepository
name: cozystack-extra
namespace: cozy-public
chartRef:
kind: OCIRepository
name: monitoring-rd
namespace: cozy-system
dashboard:
category: Administration
singular: Monitoring

View File

@@ -13,12 +13,10 @@ spec:
prefix: mysql-
labels:
cozystack.io/ui: "true"
chart:
name: mysql
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
chartRef:
kind: OCIRepository
name: mysql-rd
namespace: cozy-system
dashboard:
category: PaaS
singular: MySQL

View File

@@ -13,12 +13,10 @@ spec:
prefix: nats-
labels:
cozystack.io/ui: "true"
chart:
name: nats
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
chartRef:
kind: OCIRepository
name: nats-rd
namespace: cozy-system
dashboard:
category: PaaS
singular: NATS

View File

@@ -13,12 +13,10 @@ spec:
prefix: postgres-
labels:
cozystack.io/ui: "true"
chart:
name: postgres
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
chartRef:
kind: OCIRepository
name: postgres-rd
namespace: cozy-system
dashboard:
category: PaaS
singular: PostgreSQL

View File

@@ -13,12 +13,10 @@ spec:
prefix: rabbitmq-
labels:
cozystack.io/ui: "true"
chart:
name: rabbitmq
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
chartRef:
kind: OCIRepository
name: rabbitmq-rd
namespace: cozy-system
dashboard:
category: PaaS
singular: RabbitMQ

View File

@@ -13,12 +13,10 @@ spec:
prefix: redis-
labels:
cozystack.io/ui: "true"
chart:
name: redis
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
chartRef:
kind: OCIRepository
name: redis-rd
namespace: cozy-system
dashboard:
category: PaaS
singular: Redis

View File

@@ -14,12 +14,10 @@ spec:
labels:
cozystack.io/ui: "true"
internal.cozystack.io/tenantmodule: "true"
chart:
name: seaweedfs
sourceRef:
kind: HelmRepository
name: cozystack-extra
namespace: cozy-public
chartRef:
kind: OCIRepository
name: seaweedfs-rd
namespace: cozy-system
dashboard:
category: Administration
singular: SeaweedFS

View File

@@ -13,12 +13,10 @@ spec:
prefix: tcp-balancer-
labels:
cozystack.io/ui: "true"
chart:
name: tcp-balancer
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
chartRef:
kind: OCIRepository
name: tcp-balancer-rd
namespace: cozy-system
dashboard:
category: NaaS
singular: TCP Balancer

View File

@@ -13,12 +13,10 @@ spec:
prefix: tenant-
labels:
cozystack.io/ui: "true"
chart:
name: tenant
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
chartRef:
kind: OCIRepository
name: tenant-rd
namespace: cozy-system
dashboard:
category: Administration
singular: Tenant

View File

@@ -13,12 +13,10 @@ spec:
prefix: virtual-machine-
labels:
cozystack.io/ui: "true"
chart:
name: virtual-machine
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
chartRef:
kind: OCIRepository
name: virtual-machine-rd
namespace: cozy-system
dashboard:
category: IaaS
singular: Virtual Machine

View File

@@ -13,12 +13,10 @@ spec:
prefix: "virtualprivatecloud-"
labels:
cozystack.io/ui: "true"
chart:
name: virtualprivatecloud
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
chartRef:
kind: OCIRepository
name: virtualprivatecloud-rd
namespace: cozy-system
dashboard:
category: IaaS
singular: VPC

View File

@@ -13,12 +13,10 @@ spec:
prefix: vm-disk-
labels:
cozystack.io/ui: "true"
chart:
name: vm-disk
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
chartRef:
kind: OCIRepository
name: vm-disk-rd
namespace: cozy-system
dashboard:
category: IaaS
singular: VM Disk

View File

@@ -13,12 +13,10 @@ spec:
prefix: vm-instance-
labels:
cozystack.io/ui: "true"
chart:
name: vm-instance
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
chartRef:
kind: OCIRepository
name: vm-instance-rd
namespace: cozy-system
dashboard:
category: IaaS
singular: VM Instance

View File

@@ -13,12 +13,10 @@ spec:
prefix: vpn-
labels:
cozystack.io/ui: "true"
chart:
name: vpn
sourceRef:
kind: HelmRepository
name: cozystack-apps
namespace: cozy-public
chartRef:
kind: OCIRepository
name: vpn-rd
namespace: cozy-system
dashboard:
category: NaaS
singular: VPN

View File

@@ -169,13 +169,10 @@ func (o *CozyServerOptions) Complete() error {
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,
},
ChartRef: config.ChartRefConfig{
Kind: crd.Spec.Release.ChartRef.Kind,
Name: crd.Spec.Release.ChartRef.Name,
Namespace: crd.Spec.Release.ChartRef.Namespace,
},
},
}

View File

@@ -38,19 +38,13 @@ type ApplicationConfig struct {
// ReleaseConfig contains the release settings.
type ReleaseConfig struct {
Prefix string `yaml:"prefix"`
Labels map[string]string `yaml:"labels"`
Chart ChartConfig `yaml:"chart"`
Prefix string `yaml:"prefix"`
Labels map[string]string `yaml:"labels"`
ChartRef ChartRefConfig `yaml:"chartRef"`
}
// ChartConfig contains the chart settings.
type ChartConfig struct {
Name string `yaml:"name"`
SourceRef SourceRefConfig `yaml:"sourceRef"`
}
// SourceRefConfig contains the reference to the chart source.
type SourceRefConfig struct {
// ChartRefConfig references a Flux source artifact for the Helm chart.
type ChartRefConfig struct {
Kind string `yaml:"kind"`
Name string `yaml:"name"`
Namespace string `yaml:"namespace"`

View File

@@ -2714,6 +2714,13 @@ func schema_pkg_apis_meta_v1_DeleteOptions(ref common.ReferenceCallback) common.
},
},
},
"ignoreStoreReadErrorWithClusterBreakingPotential": {
SchemaProps: spec.SchemaProps{
Description: "if set to true, it will trigger an unsafe deletion of the resource in case the normal deletion flow fails with a corrupt object error. A resource is considered corrupt if it can not be retrieved from the underlying storage successfully because of a) its data can not be transformed e.g. decryption failure, or b) it fails to decode into an object. NOTE: unsafe deletion ignores finalizer constraints, skips precondition checks, and removes the object from the storage. WARNING: This may potentially break the cluster if the workload associated with the resource being unsafe-deleted relies on normal deletion flow. Use only if you REALLY know what you are doing. The default value is false, and the user must opt in to enable it",
Type: []string{"boolean"},
Format: "",
},
},
},
},
},
@@ -4601,16 +4608,46 @@ func schema_k8sio_apimachinery_pkg_version_Info(ref common.ReferenceCallback) co
Properties: map[string]spec.Schema{
"major": {
SchemaProps: spec.SchemaProps{
Default: "",
Type: []string{"string"},
Format: "",
Description: "Major is the major version of the binary version",
Default: "",
Type: []string{"string"},
Format: "",
},
},
"minor": {
SchemaProps: spec.SchemaProps{
Default: "",
Type: []string{"string"},
Format: "",
Description: "Minor is the minor version of the binary version",
Default: "",
Type: []string{"string"},
Format: "",
},
},
"emulationMajor": {
SchemaProps: spec.SchemaProps{
Description: "EmulationMajor is the major version of the emulation version",
Type: []string{"string"},
Format: "",
},
},
"emulationMinor": {
SchemaProps: spec.SchemaProps{
Description: "EmulationMinor is the minor version of the emulation version",
Type: []string{"string"},
Format: "",
},
},
"minCompatibilityMajor": {
SchemaProps: spec.SchemaProps{
Description: "MinCompatibilityMajor is the major version of the minimum compatibility version",
Type: []string{"string"},
Format: "",
},
},
"minCompatibilityMinor": {
SchemaProps: spec.SchemaProps{
Description: "MinCompatibilityMinor is the minor version of the minimum compatibility version",
Type: []string{"string"},
Format: "",
},
},
"gitVersion": {

View File

@@ -22,6 +22,11 @@ const (
HRLabel = "helm.toolkit.fluxcd.io/name"
)
// AppMapper maps HelmRelease to application metadata.
type AppMapper interface {
Map(*helmv2.HelmRelease) (apiVersion, kind, prefix string, err error)
}
type ObjectID struct {
APIVersion string
Kind string

View File

@@ -4,8 +4,10 @@ import (
"context"
"fmt"
"os"
"strings"
"testing"
helmv2 "github.com/fluxcd/helm-controller/api/v2"
"github.com/go-logr/logr"
"github.com/go-logr/zapr"
"go.uber.org/zap"
@@ -41,12 +43,41 @@ func init() {
ctx = logr.NewContext(context.Background(), l)
}
// labelsMapper implements AppMapper using HelmRelease labels.
type labelsMapper struct{}
func (m *labelsMapper) Map(hr *helmv2.HelmRelease) (string, string, string, error) {
if hr.Labels == nil {
return "", "", "", fmt.Errorf("cannot map helm release %s/%s: labels are nil", hr.Namespace, hr.Name)
}
appKind, ok := hr.Labels["apps.cozystack.io/application.kind"]
if !ok {
return "", "", "", fmt.Errorf("cannot map helm release %s/%s: missing application.kind label", hr.Namespace, hr.Name)
}
appGroup, ok := hr.Labels["apps.cozystack.io/application.group"]
if !ok {
return "", "", "", fmt.Errorf("cannot map helm release %s/%s: missing application.group label", hr.Namespace, hr.Name)
}
appName, ok := hr.Labels["apps.cozystack.io/application.name"]
if !ok {
return "", "", "", fmt.Errorf("cannot map helm release %s/%s: missing application.name label", hr.Namespace, hr.Name)
}
apiVersion := fmt.Sprintf("%s/v1alpha1", appGroup)
prefix := strings.TrimSuffix(hr.Name, appName)
return apiVersion, appKind, prefix, nil
}
func TestWalkingOwnershipGraph(t *testing.T) {
obj, err := dynClient.Resource(schema.GroupVersionResource{"", "v1", "pods"}).Namespace(os.Args[1]).Get(ctx, os.Args[2], metav1.GetOptions{})
if err != nil {
t.Fatal(err)
}
nodes := WalkOwnershipGraph(ctx, dynClient, mapper, &stubMapper{}, obj)
nodes := WalkOwnershipGraph(ctx, dynClient, mapper, &labelsMapper{}, obj)
for _, node := range nodes {
fmt.Printf("%#v\n", node)
}

View File

@@ -1,49 +0,0 @@
package lineage
import (
"fmt"
"strings"
helmv2 "github.com/fluxcd/helm-controller/api/v2"
)
type AppMapper interface {
Map(*helmv2.HelmRelease) (apiVersion, kind, prefix string, err error)
}
type stubMapper struct{}
var stubMapperMap = map[string]string{
"cozystack-extra/bootbox": "apps.cozystack.io/v1alpha1/BootBox/",
"cozystack-apps/bucket": "apps.cozystack.io/v1alpha1/Bucket/bucket-",
"cozystack-apps/clickhouse": "apps.cozystack.io/v1alpha1/ClickHouse/clickhouse-",
"cozystack-extra/etcd": "apps.cozystack.io/v1alpha1/Etcd/",
"cozystack-apps/ferretdb": "apps.cozystack.io/v1alpha1/FerretDB/ferretdb-",
"cozystack-apps/http-cache": "apps.cozystack.io/v1alpha1/HTTPCache/http-cache-",
"cozystack-extra/info": "apps.cozystack.io/v1alpha1/Info/",
"cozystack-extra/ingress": "apps.cozystack.io/v1alpha1/Ingress/",
"cozystack-apps/kafka": "apps.cozystack.io/v1alpha1/Kafka/kafka-",
"cozystack-apps/kubernetes": "apps.cozystack.io/v1alpha1/Kubernetes/kubernetes-",
"cozystack-extra/monitoring": "apps.cozystack.io/v1alpha1/Monitoring/",
"cozystack-apps/mysql": "apps.cozystack.io/v1alpha1/MySQL/mysql-",
"cozystack-apps/nats": "apps.cozystack.io/v1alpha1/NATS/nats-",
"cozystack-apps/postgres": "apps.cozystack.io/v1alpha1/Postgres/postgres-",
"cozystack-apps/rabbitmq": "apps.cozystack.io/v1alpha1/RabbitMQ/rabbitmq-",
"cozystack-apps/redis": "apps.cozystack.io/v1alpha1/Redis/redis-",
"cozystack-extra/seaweedfs": "apps.cozystack.io/v1alpha1/SeaweedFS/",
"cozystack-apps/tcp-balancer": "apps.cozystack.io/v1alpha1/TCPBalancer/tcp-balancer-",
"cozystack-apps/tenant": "apps.cozystack.io/v1alpha1/Tenant/tenant-",
"cozystack-apps/virtual-machine": "apps.cozystack.io/v1alpha1/VirtualMachine/virtual-machine-",
"cozystack-apps/vm-disk": "apps.cozystack.io/v1alpha1/VMDisk/vm-disk-",
"cozystack-apps/vm-instance": "apps.cozystack.io/v1alpha1/VMInstance/vm-instance-",
"cozystack-apps/vpn": "apps.cozystack.io/v1alpha1/VPN/vpn-",
}
func (s *stubMapper) Map(hr *helmv2.HelmRelease) (string, string, string, error) {
val, ok := stubMapperMap[hr.Spec.Chart.Spec.SourceRef.Name+"/"+hr.Spec.Chart.Spec.Chart]
if !ok {
return "", "", "", fmt.Errorf("cannot map helm release %s/%s to dynamic app", hr.Namespace, hr.Name)
}
split := strings.Split(val, "/")
return strings.Join(split[:2], "/"), split[2], split[3], nil
}

View File

@@ -963,17 +963,10 @@ func (r *REST) convertApplicationToHelmRelease(app *appsv1alpha1.Application) (*
UID: app.UID,
},
Spec: helmv2.HelmReleaseSpec{
Chart: &helmv2.HelmChartTemplate{
Spec: helmv2.HelmChartTemplateSpec{
Chart: r.releaseConfig.Chart.Name,
Version: ">= 0.0.0-0",
ReconcileStrategy: "Revision",
SourceRef: helmv2.CrossNamespaceObjectReference{
Kind: r.releaseConfig.Chart.SourceRef.Kind,
Name: r.releaseConfig.Chart.SourceRef.Name,
Namespace: r.releaseConfig.Chart.SourceRef.Namespace,
},
},
ChartRef: &helmv2.CrossNamespaceSourceReference{
Kind: r.releaseConfig.ChartRef.Kind,
Name: r.releaseConfig.ChartRef.Name,
Namespace: r.releaseConfig.ChartRef.Namespace,
},
Interval: metav1.Duration{Duration: 5 * time.Minute},
Install: &helmv2.Install{
@@ -1085,11 +1078,19 @@ func (r *REST) buildTableFromApplication(app appsv1alpha1.Application) metav1.Ta
return table
}
// getVersion returns the application version or a placeholder if unknown
// getVersion extracts and returns only the revision from the version string
// If version is in format "0.1.4+abcdef", returns "abcdef"
// Otherwise returns the original string or "<unknown>" if empty
func getVersion(version string) string {
if version == "" {
return "<unknown>"
}
// Check if version contains "+" separator
if idx := strings.LastIndex(version, "+"); idx >= 0 && idx < len(version)-1 {
// Return only the part after "+"
return version[idx+1:]
}
// If no "+" found, return original version
return version
}

View File

@@ -20,6 +20,7 @@ import (
"context"
"fmt"
"net/http"
"strings"
"sync"
"time"
@@ -666,11 +667,19 @@ func (r *REST) buildTableFromTenantModule(module corev1alpha1.TenantModule) meta
return table
}
// getVersion returns the module version or a placeholder if unknown
// getVersion extracts and returns only the revision from the version string
// If version is in format "0.1.4+abcdef", returns "abcdef"
// Otherwise returns the original string or "<unknown>" if empty
func getVersion(version string) string {
if version == "" {
return "<unknown>"
}
// Check if version contains "+" separator
if idx := strings.LastIndex(version, "+"); idx >= 0 && idx < len(version)-1 {
// Return only the part after "+"
return version[idx+1:]
}
// If no "+" found, return original version
return version
}

View File

@@ -1,71 +0,0 @@
#!/bin/sh
set -o pipefail
set -e
BUNDLE=$(set -x; kubectl get configmap -n cozy-system cozystack -o 'go-template={{index .data "bundle-name"}}')
VERSION=$(find scripts/migrations -mindepth 1 -maxdepth 1 -type f | sort -V | awk -F/ 'END {print $NF+1}')
run_migrations() {
if ! kubectl get configmap -n cozy-system cozystack-version; then
kubectl create configmap -n cozy-system cozystack-version --from-literal=version="$VERSION" --dry-run=client -o yaml | kubectl create -f-
return
fi
current_version=$(kubectl get configmap -n cozy-system cozystack-version -o jsonpath='{.data.version}') || true
until [ "$current_version" = "$VERSION" ]; do
echo "run migration: $current_version --> $VERSION"
chmod +x scripts/migrations/$current_version
scripts/migrations/$current_version
current_version=$(kubectl get configmap -n cozy-system cozystack-version -o jsonpath='{.data.version}')
done
}
install_flux() {
if [ "$INSTALL_FLUX" != "true" ]; then
return
fi
make -C packages/core/flux-aio apply
wait_for_crds helmreleases.helm.toolkit.fluxcd.io helmrepositories.source.toolkit.fluxcd.io
}
wait_for_crds() {
timeout 60 sh -c "until kubectl get crd $*; do sleep 1; done"
}
cd "$(dirname "$0")/.."
# Run migrations
run_migrations
# Install namespaces
make -C packages/core/platform namespaces-apply
# Install fluxcd
install_flux
# Install fluxcd certificates
./scripts/issue-flux-certificates.sh
# Install platform chart
make -C packages/core/platform reconcile
# Reconcile Helm repositories
kubectl annotate helmrepositories.source.toolkit.fluxcd.io -A -l cozystack.io/repository reconcile.fluxcd.io/requestedAt=$(date +"%Y-%m-%dT%H:%M:%SZ") --overwrite
# Unsuspend all Cozystack managed charts
kubectl get hr -A -o go-template='{{ range .items }}{{ if .spec.suspend }}{{ .spec.chart.spec.sourceRef.namespace }}/{{ .spec.chart.spec.sourceRef.name }} {{ .metadata.namespace }} {{ .metadata.name }}{{ "\n" }}{{ end }}{{ end }}' | while read repo namespace name; do
case "$repo" in
cozy-system/cozystack-system|cozy-public/cozystack-extra|cozy-public/cozystack-apps)
kubectl patch hr -n "$namespace" "$name" -p '{"spec": {"suspend": null}}' --type=merge --field-manager=flux-client-side-apply
;;
esac
done
# Update all Cozystack managed charts to latest version
kubectl get hr -A -l cozystack.io/ui=true --no-headers | awk '{print "kubectl patch helmrelease -n " $1 " " $2 " --type=merge -p '\''{\"spec\":{\"chart\":{\"spec\":{\"version\":\">= 0.0.0-0\"}}}}'\'' "}' | sh -x
# Reconcile platform chart
trap 'exit' INT TERM
while true; do
sleep 60 & wait
make -C packages/core/platform reconcile
done