diff --git a/.github/workflows/auto-release.yaml b/.github/workflows/auto-release.yaml index 19d4b460..44ca8ca6 100644 --- a/.github/workflows/auto-release.yaml +++ b/.github/workflows/auto-release.yaml @@ -20,6 +20,14 @@ jobs: pull-requests: read steps: + - name: Generate GitHub App token + id: app-token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ secrets.COZYSTACK_CI_APP_ID }} + private-key: ${{ secrets.COZYSTACK_CI_PRIVATE_KEY }} + owner: cozystack + - name: Checkout code uses: actions/checkout@v4 with: @@ -28,27 +36,27 @@ jobs: - name: Configure git env: - GH_PAT: ${{ secrets.GH_PAT }} + APP_TOKEN: ${{ steps.app-token.outputs.token }} run: | - git config user.name "cozystack-bot" - git config user.email "217169706+cozystack-bot@users.noreply.github.com" - git remote set-url origin https://cozystack-bot:${GH_PAT}@github.com/${GITHUB_REPOSITORY} + git config user.name "cozystack-ci[bot]" + git config user.email "274107086+cozystack-ci[bot]@users.noreply.github.com" + git remote set-url origin https://x-access-token:${APP_TOKEN}@github.com/${GITHUB_REPOSITORY} git config --unset-all http.https://github.com/.extraheader || true - name: Process release branches uses: actions/github-script@v7 env: - GH_PAT: ${{ secrets.GH_PAT }} + APP_TOKEN: ${{ steps.app-token.outputs.token }} with: - github-token: ${{ secrets.GH_PAT }} + github-token: ${{ steps.app-token.outputs.token }} script: | const { execSync } = require('child_process'); - // Configure git to use PAT for authentication - execSync('git config user.name "cozystack-bot"', { encoding: 'utf8' }); - execSync('git config user.email "217169706+cozystack-bot@users.noreply.github.com"', { encoding: 'utf8' }); - execSync(`git remote set-url origin https://cozystack-bot:${process.env.GH_PAT}@github.com/${process.env.GITHUB_REPOSITORY}`, { encoding: 'utf8' }); - // Remove GITHUB_TOKEN extraheader to ensure PAT is used (needed to trigger other workflows) + // Configure git to use GitHub App token for authentication + execSync('git config user.name "cozystack-ci[bot]"', { encoding: 'utf8' }); + execSync('git config user.email "274107086+cozystack-ci[bot]@users.noreply.github.com"', { encoding: 'utf8' }); + execSync(`git remote set-url origin https://x-access-token:${process.env.APP_TOKEN}@github.com/${process.env.GITHUB_REPOSITORY}`, { encoding: 'utf8' }); + // Remove GITHUB_TOKEN extraheader to ensure App token is used (needed to trigger other workflows) execSync('git config --unset-all http.https://github.com/.extraheader || true', { encoding: 'utf8' }); // Get all release-X.Y branches diff --git a/.github/workflows/pull-requests-release.yaml b/.github/workflows/pull-requests-release.yaml index 72f31b54..bb7f5da5 100644 --- a/.github/workflows/pull-requests-release.yaml +++ b/.github/workflows/pull-requests-release.yaml @@ -23,6 +23,14 @@ jobs: contains(github.event.pull_request.labels.*.name, 'release') steps: + - name: Generate GitHub App token + id: app-token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ secrets.COZYSTACK_CI_APP_ID }} + private-key: ${{ secrets.COZYSTACK_CI_PRIVATE_KEY }} + owner: cozystack + # Extract tag from branch name (branch = release-X.Y.Z*) - name: Extract tag from branch name id: get_tag @@ -47,11 +55,11 @@ jobs: - name: Create tag on merge commit env: - GH_PAT: ${{ secrets.GH_PAT }} + APP_TOKEN: ${{ steps.app-token.outputs.token }} run: | - git config user.name "cozystack-bot" - git config user.email "217169706+cozystack-bot@users.noreply.github.com" - git remote set-url origin https://cozystack-bot:${GH_PAT}@github.com/${GITHUB_REPOSITORY} + git config user.name "cozystack-ci[bot]" + git config user.email "274107086+cozystack-ci[bot]@users.noreply.github.com" + git remote set-url origin https://x-access-token:${APP_TOKEN}@github.com/${GITHUB_REPOSITORY} git tag -f ${{ steps.get_tag.outputs.tag }} ${{ github.sha }} git push -f origin ${{ steps.get_tag.outputs.tag }} @@ -59,7 +67,7 @@ jobs: - name: Ensure maintenance branch release-X.Y uses: actions/github-script@v7 with: - github-token: ${{ secrets.GH_PAT }} + github-token: ${{ steps.app-token.outputs.token }} script: | const tag = '${{ steps.get_tag.outputs.tag }}'; // e.g. v0.1.3 or v0.1.3-rc3 const match = tag.match(/^v(\d+)\.(\d+)\.\d+(?:[-\w\.]+)?$/); diff --git a/.github/workflows/pull-requests.yaml b/.github/workflows/pull-requests.yaml index b9b7b0ac..933c29ec 100644 --- a/.github/workflows/pull-requests.yaml +++ b/.github/workflows/pull-requests.yaml @@ -85,6 +85,14 @@ jobs: disk_id: ${{ steps.fetch_assets.outputs.disk_id }} steps: + - name: Generate GitHub App token + id: app-token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ secrets.COZYSTACK_CI_APP_ID }} + private-key: ${{ secrets.COZYSTACK_CI_PRIVATE_KEY }} + owner: cozystack + - name: Checkout code if: contains(github.event.pull_request.labels.*.name, 'release') uses: actions/checkout@v4 @@ -111,7 +119,7 @@ jobs: id: fetch_assets uses: actions/github-script@v7 with: - github-token: ${{ secrets.GH_PAT }} + github-token: ${{ steps.app-token.outputs.token }} script: | const tag = '${{ steps.get_tag.outputs.tag }}'; const releases = await github.rest.repos.listReleases({ @@ -144,6 +152,15 @@ jobs: if: ${{ always() && (needs.build.result == 'success' || needs.resolve_assets.result == 'success') }} steps: + - name: Generate GitHub App token + if: contains(github.event.pull_request.labels.*.name, 'release') + id: app-token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ secrets.COZYSTACK_CI_APP_ID }} + private-key: ${{ secrets.COZYSTACK_CI_PRIVATE_KEY }} + owner: cozystack + # ▸ Checkout and prepare the codebase - name: Checkout code uses: actions/checkout@v4 @@ -173,11 +190,11 @@ jobs: if: contains(github.event.pull_request.labels.*.name, 'release') run: | mkdir -p _out/assets - curl -sSL -H "Authorization: token ${GH_PAT}" -H "Accept: application/octet-stream" \ + curl -sSL -H "Authorization: token ${APP_TOKEN}" -H "Accept: application/octet-stream" \ -o _out/assets/nocloud-amd64.raw.xz \ "https://api.github.com/repos/${GITHUB_REPOSITORY}/releases/assets/${{ needs.resolve_assets.outputs.disk_id }}" env: - GH_PAT: ${{ secrets.GH_PAT }} + APP_TOKEN: ${{ steps.app-token.outputs.token }} - name: Set sandbox ID run: echo "SANDBOX_NAME=cozy-e2e-sandbox-$(echo "${GITHUB_REPOSITORY}:${GITHUB_WORKFLOW}:${GITHUB_REF}" | sha256sum | cut -c1-10)" >> $GITHUB_ENV diff --git a/.github/workflows/tags.yaml b/.github/workflows/tags.yaml index ad9dd0a9..bba18c2d 100644 --- a/.github/workflows/tags.yaml +++ b/.github/workflows/tags.yaml @@ -23,6 +23,14 @@ jobs: actions: write steps: + - name: Generate GitHub App token + id: app-token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ secrets.COZYSTACK_CI_APP_ID }} + private-key: ${{ secrets.COZYSTACK_CI_PRIVATE_KEY }} + owner: cozystack + # Check if a non-draft release with this tag already exists - name: Check if release already exists id: check_release @@ -113,16 +121,31 @@ jobs: - name: Commit release artifacts if: steps.check_release.outputs.skip == 'false' env: - GH_PAT: ${{ secrets.GH_PAT }} + APP_TOKEN: ${{ steps.app-token.outputs.token }} run: | - git config user.name "cozystack-bot" - git config user.email "217169706+cozystack-bot@users.noreply.github.com" - git remote set-url origin https://cozystack-bot:${GH_PAT}@github.com/${GITHUB_REPOSITORY} + git config user.name "cozystack-ci[bot]" + git config user.email "274107086+cozystack-ci[bot]@users.noreply.github.com" + git remote set-url origin https://x-access-token:${APP_TOKEN}@github.com/${GITHUB_REPOSITORY} git config --unset-all http.https://github.com/.extraheader || true git add . git commit -m "Prepare release ${GITHUB_REF#refs/tags/}" -s || echo "No changes to commit" git push origin HEAD || true + # Tag the api/apps/v1alpha1 submodule for pkg.go.dev + - name: Tag API submodule + if: steps.check_release.outputs.skip == 'false' + env: + APP_TOKEN: ${{ steps.app-token.outputs.token }} + run: | + VTAG="${{ steps.tag.outputs.tag }}" + SUBTAG="api/apps/v1alpha1/${VTAG}" + git config user.name "cozystack-ci[bot]" + git config user.email "274107086+cozystack-ci[bot]@users.noreply.github.com" + git remote set-url origin https://x-access-token:${APP_TOKEN}@github.com/${GITHUB_REPOSITORY} + TARGET="$(git rev-parse "${VTAG}^{}")" + git tag -f "${SUBTAG}" "$TARGET" + git push -f origin "refs/tags/${SUBTAG}" + # Create or reuse draft release - name: Create / reuse draft release if: steps.check_release.outputs.skip == 'false' @@ -167,11 +190,11 @@ jobs: - name: Create release branch if: steps.check_release.outputs.skip == 'false' env: - GH_PAT: ${{ secrets.GH_PAT }} + APP_TOKEN: ${{ steps.app-token.outputs.token }} run: | - git config user.name "cozystack-bot" - git config user.email "217169706+cozystack-bot@users.noreply.github.com" - git remote set-url origin https://cozystack-bot:${GH_PAT}@github.com/${GITHUB_REPOSITORY} + git config user.name "cozystack-ci[bot]" + git config user.email "274107086+cozystack-ci[bot]@users.noreply.github.com" + git remote set-url origin https://x-access-token:${APP_TOKEN}@github.com/${GITHUB_REPOSITORY} BRANCH="release-${GITHUB_REF#refs/tags/v}" git branch -f "$BRANCH" git push -f origin "$BRANCH" @@ -181,7 +204,7 @@ jobs: if: steps.check_release.outputs.skip == 'false' uses: actions/github-script@v7 with: - github-token: ${{ secrets.GH_PAT }} + github-token: ${{ steps.app-token.outputs.token }} script: | const version = context.ref.replace('refs/tags/v', ''); const base = '${{ steps.get_base.outputs.branch }}'; @@ -223,6 +246,14 @@ jobs: pull-requests: write if: needs.prepare-release.result == 'success' steps: + - name: Generate GitHub App token + id: app-token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ secrets.COZYSTACK_CI_APP_ID }} + private-key: ${{ secrets.COZYSTACK_CI_PRIVATE_KEY }} + owner: cozystack + - name: Parse tag id: tag uses: actions/github-script@v7 @@ -245,7 +276,7 @@ jobs: ref: main fetch-depth: 0 fetch-tags: true - token: ${{ secrets.GH_PAT }} + token: ${{ steps.app-token.outputs.token }} - name: Check if changelog already exists id: check_changelog @@ -273,7 +304,7 @@ jobs: if: steps.check_changelog.outputs.exists == 'false' env: COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} - GH_TOKEN: ${{ secrets.GH_PAT }} + GH_TOKEN: ${{ steps.app-token.outputs.token }} run: | copilot --prompt "prepare changelog file for tagged release v${{ steps.tag.outputs.version }}, use @docs/agents/changelog.md for it. Create the changelog file at docs/changelogs/v${{ steps.tag.outputs.version }}.md" \ --allow-all-tools --allow-all-paths < /dev/null @@ -281,11 +312,11 @@ jobs: - name: Create changelog branch and commit if: steps.check_changelog.outputs.exists == 'false' env: - GH_PAT: ${{ secrets.GH_PAT }} + APP_TOKEN: ${{ steps.app-token.outputs.token }} run: | - git config user.name "cozystack-bot" - git config user.email "217169706+cozystack-bot@users.noreply.github.com" - git remote set-url origin https://cozystack-bot:${GH_PAT}@github.com/${GITHUB_REPOSITORY} + git config user.name "cozystack-ci[bot]" + git config user.email "274107086+cozystack-ci[bot]@users.noreply.github.com" + git remote set-url origin https://x-access-token:${APP_TOKEN}@github.com/${GITHUB_REPOSITORY} CHANGELOG_FILE="docs/changelogs/v${{ steps.tag.outputs.version }}.md" CHANGELOG_BRANCH="changelog-v${{ steps.tag.outputs.version }}" @@ -320,7 +351,7 @@ jobs: if: steps.check_changelog.outputs.exists == 'false' uses: actions/github-script@v7 with: - github-token: ${{ secrets.GH_PAT }} + github-token: ${{ steps.app-token.outputs.token }} script: | const version = '${{ steps.tag.outputs.version }}'; const changelogBranch = `changelog-v${version}`; @@ -370,3 +401,82 @@ jobs: console.log(`Created PR #${pr.data.number} for changelog`); } + + update-website-docs: + name: Update Website Docs + runs-on: [self-hosted] + needs: [generate-changelog, prepare-release] + if: needs.generate-changelog.result == 'success' && needs.prepare-release.outputs.skip != 'true' + permissions: + contents: read + steps: + - name: Generate GitHub App token + id: app-token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ secrets.COZYSTACK_CI_APP_ID }} + private-key: ${{ secrets.COZYSTACK_CI_PRIVATE_KEY }} + owner: cozystack + + - name: Parse tag + id: tag + uses: actions/github-script@v7 + with: + script: | + const ref = context.ref.replace('refs/tags/', ''); + const m = ref.match(/^v(\d+\.\d+\.\d+)(-(?:alpha|beta|rc)\.\d+)?$/); + if (!m) { + core.setFailed(`❌ tag '${ref}' must match 'vX.Y.Z' or 'vX.Y.Z-(alpha|beta|rc).N'`); + return; + } + const version = m[1] + (m[2] ?? ''); + core.setOutput('tag', ref); // v0.22.0 + core.setOutput('version', version); // 0.22.0 + + - name: Checkout website repo + uses: actions/checkout@v4 + with: + repository: cozystack/website + token: ${{ steps.app-token.outputs.token }} + ref: main + + - name: Update docs from release branch + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + run: make update-all BRANCH=release-${{ steps.tag.outputs.version }} RELEASE_TAG=${{ steps.tag.outputs.tag }} + + - name: Commit and push + id: commit + run: | + git config user.name "cozystack-ci[bot]" + git config user.email "274107086+cozystack-ci[bot]@users.noreply.github.com" + git add content + if git diff --cached --quiet; then + echo "No changes to commit" + echo "changed=false" >> $GITHUB_OUTPUT + exit 0 + fi + BRANCH="update-docs-v${{ steps.tag.outputs.version }}" + git branch -D "$BRANCH" 2>/dev/null || true + git checkout -b "$BRANCH" + git commit --signoff -m "[docs] Update managed apps reference for v${{ steps.tag.outputs.version }}" + git push --force --set-upstream origin "$BRANCH" + echo "changed=true" >> $GITHUB_OUTPUT + + - name: Open pull request + if: steps.commit.outputs.changed == 'true' + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + run: | + BRANCH="update-docs-v${{ steps.tag.outputs.version }}" + pr_state=$(gh pr view "$BRANCH" --repo cozystack/website --json state --jq .state 2>/dev/null || echo "") + if [[ "$pr_state" == "OPEN" ]]; then + echo "PR already open, skipping creation." + else + gh pr create \ + --repo cozystack/website \ + --title "[docs] Update managed apps reference for v${{ steps.tag.outputs.version }}" \ + --body "Automated docs update for release \`v${{ steps.tag.outputs.version }}\`." \ + --head "update-docs-v${{ steps.tag.outputs.version }}" \ + --base main + fi diff --git a/hack/common-envs.mk b/hack/common-envs.mk index 56eb5478..9b8db5db 100644 --- a/hack/common-envs.mk +++ b/hack/common-envs.mk @@ -6,13 +6,13 @@ else endif REGISTRY ?= ghcr.io/cozystack/cozystack -TAG = $(shell git describe --tags --exact-match 2>/dev/null || echo latest) +TAG = $(shell git describe --tags --exact-match --match 'v*' 2>/dev/null || echo latest) PUSH := 1 LOAD := 0 BUILDER ?= PLATFORM ?= BUILDX_EXTRA_ARGS ?= -COZYSTACK_VERSION = $(patsubst v%,%,$(shell git describe --tags)) +COZYSTACK_VERSION = $(patsubst v%,%,$(shell git describe --tags --match 'v*')) BUILDX_ARGS := --provenance=false --push=$(PUSH) --load=$(LOAD) \ --label org.opencontainers.image.source=https://github.com/cozystack/cozystack \ @@ -28,6 +28,6 @@ endef ifeq ($(COZYSTACK_VERSION),) $(shell git remote add upstream https://github.com/cozystack/cozystack.git || true) $(shell git fetch upstream --tags) - COZYSTACK_VERSION = $(patsubst v%,%,$(shell git describe --tags)) + COZYSTACK_VERSION = $(patsubst v%,%,$(shell git describe --tags --match 'v*')) endif diff --git a/internal/controller/dashboard/marketplacepanel.go b/internal/controller/dashboard/marketplacepanel.go index fcfff799..14684afc 100644 --- a/internal/controller/dashboard/marketplacepanel.go +++ b/internal/controller/dashboard/marketplacepanel.go @@ -68,31 +68,46 @@ func (m *Manager) ensureMarketplacePanel(ctx context.Context, crd *cozyv1alpha1. tags[i] = t } - specMap := map[string]any{ - "description": d.Description, - "name": displayName, - "type": "nonCrd", - "apiGroup": "apps.cozystack.io", - "apiVersion": "v1alpha1", - "plural": app.Plural, // e.g., "buckets" - "disabled": false, - "hidden": false, - "tags": tags, - "icon": d.Icon, - } - - specBytes, err := json.Marshal(specMap) - if err != nil { - return reconcile.Result{}, err - } - - _, err = controllerutil.CreateOrUpdate(ctx, m.Client, mp, func() error { + _, err := controllerutil.CreateOrUpdate(ctx, m.Client, mp, func() error { if err := controllerutil.SetOwnerReference(crd, mp, m.Scheme); err != nil { return err } // Add dashboard labels to dynamic resources m.addDashboardLabels(mp, crd, ResourceTypeDynamic) + // Preserve user-set disabled/hidden values from existing resource + disabled := false + hidden := false + if mp.Spec.Raw != nil { + var existing map[string]any + if err := json.Unmarshal(mp.Spec.Raw, &existing); err == nil { + if v, ok := existing["disabled"].(bool); ok { + disabled = v + } + if v, ok := existing["hidden"].(bool); ok { + hidden = v + } + } + } + + specMap := map[string]any{ + "description": d.Description, + "name": displayName, + "type": "nonCrd", + "apiGroup": "apps.cozystack.io", + "apiVersion": "v1alpha1", + "plural": app.Plural, // e.g., "buckets" + "disabled": disabled, + "hidden": hidden, + "tags": tags, + "icon": d.Icon, + } + + specBytes, err := json.Marshal(specMap) + if err != nil { + return err + } + // Only update spec if it's different to avoid unnecessary updates newSpec := dashv1alpha1.ArbitrarySpec{ JSON: apiextv1.JSON{Raw: specBytes}, diff --git a/internal/controller/dashboard/sidebar.go b/internal/controller/dashboard/sidebar.go index 1f1c1670..90721b3d 100644 --- a/internal/controller/dashboard/sidebar.go +++ b/internal/controller/dashboard/sidebar.go @@ -38,6 +38,23 @@ func (m *Manager) ensureSidebar(ctx context.Context, crd *cozyv1alpha1.Applicati } all = crdList.Items + // 1b) Fetch all MarketplacePanels to determine which resources are hidden + hiddenResources := map[string]bool{} + var mpList dashv1alpha1.MarketplacePanelList + if err := m.List(ctx, &mpList, &client.ListOptions{}); err == nil { + for i := range mpList.Items { + mp := &mpList.Items[i] + if mp.Spec.Raw != nil { + var spec map[string]any + if err := json.Unmarshal(mp.Spec.Raw, &spec); err == nil { + if hidden, ok := spec["hidden"].(bool); ok && hidden { + hiddenResources[mp.Name] = true + } + } + } + } + } + // 2) Build category -> []item map (only for CRDs with spec.dashboard != nil) type item struct { Key string @@ -63,6 +80,11 @@ func (m *Manager) ensureSidebar(ctx context.Context, crd *cozyv1alpha1.Applicati plural := pickPlural(kind, def) lowerKind := strings.ToLower(kind) + // Skip resources hidden via MarketplacePanel + if hiddenResources[def.Name] { + continue + } + // Check if this resource is a module if def.Spec.Dashboard.Module { // Special case: info should have its own keysAndTags, not be in modules diff --git a/internal/controller/dashboard/static_refactored.go b/internal/controller/dashboard/static_refactored.go index b025509d..06c4239f 100644 --- a/internal/controller/dashboard/static_refactored.go +++ b/internal/controller/dashboard/static_refactored.go @@ -154,6 +154,14 @@ func CreateAllCustomColumnsOverrides() []*dashboardv1alpha1.CustomColumnsOverrid createStringColumn("Version", ".status.version"), }), + // Factory service details endpointslice (Pod serving table) + createCustomColumnsOverride("factory-kube-service-details-endpointslice", []any{ + createStringColumn("Pod", ".targetRef.name"), + createArrayColumn("Addresses", ".addresses"), + createBoolColumn("Ready", ".conditions.ready"), + createStringColumn("Node", ".nodeName"), + }), + // Factory service details port mapping createCustomColumnsOverride("factory-kube-service-details-port-mapping", []any{ createStringColumn("Name", ".name"), @@ -1924,12 +1932,12 @@ func CreateAllFactories() []*dashboardv1alpha1.Factory { map[string]any{ "type": "EnrichedTable", "data": map[string]any{ - "id": "external-ips-table", - "fetchUrl": "/api/clusters/{2}/k8s/api/v1/namespaces/{3}/services", - "clusterNamePartOfUrl": "{2}", - "baseprefix": "/openapi-ui", - "customizationId": "factory-details-v1.services", - "pathToItems": []any{"items"}, + "id": "external-ips-table", + "fetchUrl": "/api/clusters/{2}/k8s/api/v1/namespaces/{3}/services", + "cluster": "{2}", + "baseprefix": "/openapi-ui", + "customizationId": "factory-details-v1.services", + "pathToItems": ".items", "fieldSelector": map[string]any{ "spec.type": "LoadBalancer", }, @@ -1985,6 +1993,10 @@ func CreateAllNavigations() []*dashboardv1alpha1.Navigation { // Namespaced API resources "base-factory-namespaced-api-networking.k8s.io-v1-ingresses": "kube-ingress-details", "base-factory-namespaced-api-cozystack.io-v1alpha1-workloadmonitors": "workloadmonitor-details", + // Backup resources (not ApplicationDefinitions, so ensureNavigation doesn't cover them) + "base-factory-namespaced-api-backups.cozystack.io-v1alpha1-plans": "plan-details", + "base-factory-namespaced-api-backups.cozystack.io-v1alpha1-backupjobs": "backupjob-details", + "base-factory-namespaced-api-backups.cozystack.io-v1alpha1-backups": "backup-details", } return []*dashboardv1alpha1.Navigation{ diff --git a/packages/apps/harbor/templates/ingress.yaml b/packages/apps/harbor/templates/ingress.yaml index bb6ef07c..70933f5f 100644 --- a/packages/apps/harbor/templates/ingress.yaml +++ b/packages/apps/harbor/templates/ingress.yaml @@ -15,7 +15,7 @@ metadata: nginx.ingress.kubernetes.io/ssl-redirect: "true" nginx.ingress.kubernetes.io/backend-protocol: "HTTP" {{- if eq $solver "http01" }} - acme.cert-manager.io/http01-ingress-class: {{ $ingress }} + acme.cert-manager.io/http01-ingress-ingressclassname: {{ $ingress }} {{- end }} cert-manager.io/cluster-issuer: {{ $clusterIssuer }} spec: diff --git a/packages/apps/http-cache/images/nginx-cache.tag b/packages/apps/http-cache/images/nginx-cache.tag index 2d0e803a..cfefd32b 100644 --- a/packages/apps/http-cache/images/nginx-cache.tag +++ b/packages/apps/http-cache/images/nginx-cache.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/nginx-cache:0.0.0@sha256:cb25e40cb665b8bbeee8cb1ec39da4c9a7452ef3f2f371912bbc0d1b1e2d40a8 +ghcr.io/cozystack/cozystack/nginx-cache:0.0.0@sha256:95b2790e6caa0f2fbad48951c30e7848c0ef7b1bc433b2e5f07c5f4940f20783 diff --git a/packages/apps/kubernetes/images/cluster-autoscaler.tag b/packages/apps/kubernetes/images/cluster-autoscaler.tag index 22598190..d9fd9a52 100644 --- a/packages/apps/kubernetes/images/cluster-autoscaler.tag +++ b/packages/apps/kubernetes/images/cluster-autoscaler.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/cluster-autoscaler:0.0.0@sha256:3753b735b0315bee90de54cb25cfebc63bd2cc90ad11ca4fdc0e70439abd5096 +ghcr.io/cozystack/cozystack/cluster-autoscaler:0.0.0@sha256:e9d0aa7e651b03a6713b380101a61832818a91b5f989da9754f58693898c4056 diff --git a/packages/apps/kubernetes/images/kubevirt-csi-driver.tag b/packages/apps/kubernetes/images/kubevirt-csi-driver.tag index 925ee9bd..f57b49bb 100644 --- a/packages/apps/kubernetes/images/kubevirt-csi-driver.tag +++ b/packages/apps/kubernetes/images/kubevirt-csi-driver.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.0.0@sha256:faaa6bcdb68196edb4baafe643679bd7d2ef35f910c639b71e06a4ecc034f232 +ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.0.0@sha256:7932ffb1dbb7334564018811d6ea2e73dd05cc203e3d807c92bb5630ea1488cf diff --git a/packages/apps/kubernetes/images/kubevirt-csi-driver/controller.go b/packages/apps/kubernetes/images/kubevirt-csi-driver/controller.go index 7192b95b..edddec09 100644 --- a/packages/apps/kubernetes/images/kubevirt-csi-driver/controller.go +++ b/packages/apps/kubernetes/images/kubevirt-csi-driver/controller.go @@ -317,11 +317,7 @@ func (w *WrappedControllerService) ControllerPublishVolume(ctx context.Context, "ownerReferences": []interface{}{vmiOwnerRef}, }, "spec": map[string]interface{}{ - "endpointSelector": map[string]interface{}{ - "matchLabels": map[string]interface{}{ - "kubevirt.io/vm": vmName, - }, - }, + "endpointSelector": buildEndpointSelector([]string{vmName}), "egress": []interface{}{ map[string]interface{}{ "toEndpoints": []interface{}{ @@ -441,6 +437,13 @@ func (w *WrappedControllerService) addCNPOwnerReference(ctx context.Context, nam if err := unstructured.SetNestedSlice(existing.Object, ownerRefs, "metadata", "ownerReferences"); err != nil { return status.Errorf(codes.Internal, "failed to set ownerReferences: %v", err) } + + // Rebuild endpointSelector to include all VMs + selector := buildEndpointSelector(vmNamesFromOwnerRefs(ownerRefs)) + if err := unstructured.SetNestedField(existing.Object, selector, "spec", "endpointSelector"); err != nil { + return status.Errorf(codes.Internal, "failed to set endpointSelector: %v", err) + } + if _, err := w.dynamicClient.Resource(ciliumNetworkPolicyGVR).Namespace(namespace).Update(ctx, existing, metav1.UpdateOptions{}); err != nil { return err } @@ -486,6 +489,13 @@ func (w *WrappedControllerService) removeCNPOwnerReference(ctx context.Context, if err := unstructured.SetNestedSlice(existing.Object, remaining, "metadata", "ownerReferences"); err != nil { return status.Errorf(codes.Internal, "failed to set ownerReferences: %v", err) } + + // Rebuild endpointSelector from remaining VMs + selector := buildEndpointSelector(vmNamesFromOwnerRefs(remaining)) + if err := unstructured.SetNestedField(existing.Object, selector, "spec", "endpointSelector"); err != nil { + return status.Errorf(codes.Internal, "failed to set endpointSelector: %v", err) + } + if _, err := w.dynamicClient.Resource(ciliumNetworkPolicyGVR).Namespace(namespace).Update(ctx, existing, metav1.UpdateOptions{}); err != nil { return err } @@ -494,6 +504,37 @@ func (w *WrappedControllerService) removeCNPOwnerReference(ctx context.Context, }) } +// buildEndpointSelector returns an endpointSelector using matchExpressions +// so that multiple VMs can be listed in a single selector. +func buildEndpointSelector(vmNames []string) map[string]interface{} { + values := make([]interface{}, len(vmNames)) + for i, name := range vmNames { + values[i] = name + } + return map[string]interface{}{ + "matchExpressions": []interface{}{ + map[string]interface{}{ + "key": "kubevirt.io/vm", + "operator": "In", + "values": values, + }, + }, + } +} + +// vmNamesFromOwnerRefs extracts VM names from ownerReferences. +func vmNamesFromOwnerRefs(ownerRefs []interface{}) []string { + var names []string + for _, ref := range ownerRefs { + if refMap, ok := ref.(map[string]interface{}); ok { + if name, ok := refMap["name"].(string); ok { + names = append(names, name) + } + } + } + return names +} + func hasRWXAccessMode(pvc *corev1.PersistentVolumeClaim) bool { for _, mode := range pvc.Spec.AccessModes { if mode == corev1.ReadWriteMany { diff --git a/packages/apps/kubernetes/images/ubuntu-container-disk.tag b/packages/apps/kubernetes/images/ubuntu-container-disk.tag index ddc7baa4..e0a9cd18 100644 --- a/packages/apps/kubernetes/images/ubuntu-container-disk.tag +++ b/packages/apps/kubernetes/images/ubuntu-container-disk.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/ubuntu-container-disk:v1.35@sha256:39f626c802dd84f95720ffb54fcd80dfb8a58ac280498870d0a1aa30d4252f94 +ghcr.io/cozystack/cozystack/ubuntu-container-disk:v1.35@sha256:9673eee5db99b537060bda711b962730fd6a89b8ba87a3d984c89574a729b7fe diff --git a/packages/apps/vm-instance/templates/vm.yaml b/packages/apps/vm-instance/templates/vm.yaml index 226e5aa7..0a7eb7c5 100644 --- a/packages/apps/vm-instance/templates/vm.yaml +++ b/packages/apps/vm-instance/templates/vm.yaml @@ -34,6 +34,12 @@ spec: metadata: annotations: kubevirt.io/allow-pod-bridge-network-live-migration: "true" + {{- $ovnIPName := printf "%s.%s" (include "virtual-machine.fullname" .) .Release.Namespace }} + {{- $ovnIP := lookup "kubeovn.io/v1" "IP" "" $ovnIPName }} + {{- if $ovnIP }} + ovn.kubernetes.io/mac_address: {{ $ovnIP.spec.macAddress | quote }} + ovn.kubernetes.io/ip_address: {{ $ovnIP.spec.ipAddress | quote }} + {{- end }} labels: {{- include "virtual-machine.labels" . | nindent 8 }} spec: diff --git a/packages/core/installer/values.yaml b/packages/core/installer/values.yaml index c8b5edd7..c6bd04f5 100644 --- a/packages/core/installer/values.yaml +++ b/packages/core/installer/values.yaml @@ -1,9 +1,9 @@ cozystackOperator: # Deployment variant: talos, generic, hosted variant: talos - image: ghcr.io/cozystack/cozystack/cozystack-operator:v1.1.0@sha256:9367001a8d1d2dcf08ae74a42ac234eaa6af18f1af64ac28ce8a5946af9c5d3f + image: ghcr.io/cozystack/cozystack/cozystack-operator:v1.1.6@sha256:8c3824a2847af62a5982694f598eed43fab11947d3c7a2dd0440a313332ce14e platformSourceUrl: 'oci://ghcr.io/cozystack/cozystack/cozystack-packages' - platformSourceRef: 'digest=sha256:7c6da38e7b99ec80d35ba2cef721ea1579f8a0824989454544fa85318bb7bf15' + platformSourceRef: 'digest=sha256:933e3f2ce1b4edad421e543d241010453cfcf5804e2605589ca3a7e8e03a2e87' # Generic variant configuration (only used when cozystackOperator.variant=generic) cozystack: # Kubernetes API server host (IP only, no protocol/port) diff --git a/packages/core/platform/images/migrations/migrations/34 b/packages/core/platform/images/migrations/migrations/34 index 57204ff0..f031d590 100755 --- a/packages/core/platform/images/migrations/migrations/34 +++ b/packages/core/platform/images/migrations/migrations/34 @@ -13,6 +13,15 @@ set -euo pipefail DEFAULT_VERSION="v3.13" + +# Skip if the CRD does not exist (rabbitmq was never installed) +if ! kubectl api-resources --api-group=apps.cozystack.io -o name 2>/dev/null | grep -q '^rabbitmqs\.'; then + echo "CRD rabbitmqs.apps.cozystack.io not found, skipping migration" + kubectl create configmap -n cozy-system cozystack-version \ + --from-literal=version=35 --dry-run=client -o yaml | kubectl apply -f- + exit 0 +fi + RABBITMQS=$(kubectl get rabbitmqs.apps.cozystack.io -A -o jsonpath='{range .items[*]}{.metadata.namespace}/{.metadata.name}{"\n"}{end}') for resource in $RABBITMQS; do NS="${resource%%/*}" diff --git a/packages/core/platform/templates/_helpers.tpl b/packages/core/platform/templates/_helpers.tpl index 684ee812..4bc02429 100644 --- a/packages/core/platform/templates/_helpers.tpl +++ b/packages/core/platform/templates/_helpers.tpl @@ -13,6 +13,8 @@ apiVersion: cozystack.io/v1alpha1 kind: Package metadata: name: {{ $name }} + annotations: + helm.sh/resource-policy: keep spec: variant: {{ $variant }} {{- if $components }} @@ -40,6 +42,8 @@ apiVersion: cozystack.io/v1alpha1 kind: Package metadata: name: {{ $name }} + annotations: + helm.sh/resource-policy: keep spec: variant: {{ $variant }} {{- end }} diff --git a/packages/core/platform/values.yaml b/packages/core/platform/values.yaml index c559af9e..4424b899 100644 --- a/packages/core/platform/values.yaml +++ b/packages/core/platform/values.yaml @@ -5,7 +5,7 @@ sourceRef: path: / migrations: enabled: false - image: ghcr.io/cozystack/cozystack/platform-migrations:v1.1.0@sha256:d7e8955c1ad8c8fbd4ce42b014c0f849d73d0c3faf0cedaac8e15d647fb2f663 + image: ghcr.io/cozystack/cozystack/platform-migrations:v1.1.6@sha256:bcbe612879cecd2ae1cef91dfff6d34d009c2f7de6592145c04a2d6d21b28f4b targetVersion: 35 # Bundle deployment configuration bundles: diff --git a/packages/core/testing/values.yaml b/packages/core/testing/values.yaml index f80ea6c5..29ed7500 100644 --- a/packages/core/testing/values.yaml +++ b/packages/core/testing/values.yaml @@ -1,2 +1,2 @@ e2e: - image: ghcr.io/cozystack/cozystack/e2e-sandbox:v1.1.0@sha256:0eae9f519669667d60b160ebb93c127843c470ad9ca3447fceaa54604503a7ba + image: ghcr.io/cozystack/cozystack/e2e-sandbox:v1.1.6@sha256:892663fe8c17596b2e01f49e13a1d76181e92f1b8d2f02b80065ba6824c6c80d diff --git a/packages/extra/bootbox/images/matchbox.tag b/packages/extra/bootbox/images/matchbox.tag index 81f52edf..0af2d7db 100644 --- a/packages/extra/bootbox/images/matchbox.tag +++ b/packages/extra/bootbox/images/matchbox.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/matchbox:v1.1.0@sha256:e4c872f6dadc2bbcb9200d04a1d9878f62502f74e979b4eae6c7203abc6d8fa6 +ghcr.io/cozystack/cozystack/matchbox:v1.1.6@sha256:7bf51ee8f8bddc90c002a95bd702c12dea94cbebca6bc9c4d2016f59799432d5 diff --git a/packages/extra/bootbox/templates/matchbox/ingress.yaml b/packages/extra/bootbox/templates/matchbox/ingress.yaml index 4262cd10..5eef3489 100644 --- a/packages/extra/bootbox/templates/matchbox/ingress.yaml +++ b/packages/extra/bootbox/templates/matchbox/ingress.yaml @@ -10,7 +10,7 @@ metadata: app: bootbox annotations: {{- if eq $solver "http01" }} - acme.cert-manager.io/http01-ingress-class: {{ $ingress }} + acme.cert-manager.io/http01-ingress-ingressclassname: {{ $ingress }} {{- end }} cert-manager.io/cluster-issuer: {{ $clusterIssuer }} {{- if .Values.whitelistHTTP }} diff --git a/packages/extra/etcd/templates/etcd-defrag.yaml b/packages/extra/etcd/templates/etcd-defrag.yaml index 089df920..0478129f 100644 --- a/packages/extra/etcd/templates/etcd-defrag.yaml +++ b/packages/extra/etcd/templates/etcd-defrag.yaml @@ -4,9 +4,14 @@ metadata: name: {{ .Release.Name }}-defrag spec: schedule: "0 * * * *" + concurrencyPolicy: Forbid + startingDeadlineSeconds: 300 successfulJobsHistoryLimit: 3 + failedJobsHistoryLimit: 1 jobTemplate: spec: + activeDeadlineSeconds: 1800 + backoffLimit: 2 template: spec: containers: diff --git a/packages/extra/seaweedfs/images/objectstorage-sidecar.tag b/packages/extra/seaweedfs/images/objectstorage-sidecar.tag index 704e9bc7..d3fcde1b 100644 --- a/packages/extra/seaweedfs/images/objectstorage-sidecar.tag +++ b/packages/extra/seaweedfs/images/objectstorage-sidecar.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/objectstorage-sidecar:v1.1.0@sha256:2a3595cd88b30af55b2000d3ca204899beecef0012b0e0402754c3914aad1f7f +ghcr.io/cozystack/cozystack/objectstorage-sidecar:v1.1.6@sha256:37036d667afc0f2d469242364dbd718478ba416f1d728f0dd8407ea9c940155a diff --git a/packages/extra/seaweedfs/templates/seaweedfs.yaml b/packages/extra/seaweedfs/templates/seaweedfs.yaml index 42441b26..2f5720ca 100644 --- a/packages/extra/seaweedfs/templates/seaweedfs.yaml +++ b/packages/extra/seaweedfs/templates/seaweedfs.yaml @@ -243,7 +243,7 @@ spec: nginx.ingress.kubernetes.io/proxy-body-size: "0" nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" {{- if eq $solver "http01" }} - acme.cert-manager.io/http01-ingress-class: {{ $ingress }} + acme.cert-manager.io/http01-ingress-ingressclassname: {{ $ingress }} {{- end }} cert-manager.io/cluster-issuer: {{ $clusterIssuer }} tls: diff --git a/packages/system/backup-controller/values.yaml b/packages/system/backup-controller/values.yaml index 03a9ce6a..2dab062a 100644 --- a/packages/system/backup-controller/values.yaml +++ b/packages/system/backup-controller/values.yaml @@ -1,5 +1,5 @@ backupController: - image: "ghcr.io/cozystack/cozystack/backup-controller:v1.1.0@sha256:8e42e29f5d30ecbef1f05cb0601c32703c5f9572b89d2c9032c1dff186e9a526" + image: "ghcr.io/cozystack/cozystack/backup-controller:v1.1.6@sha256:c1db79c316b6863a0b9fb32e3a42e95623b1d99383c71d15ca927c02b558a7fb" replicas: 2 debug: false metrics: diff --git a/packages/system/backupstrategy-controller/values.yaml b/packages/system/backupstrategy-controller/values.yaml index 1cb94695..35ff63ec 100644 --- a/packages/system/backupstrategy-controller/values.yaml +++ b/packages/system/backupstrategy-controller/values.yaml @@ -1,5 +1,5 @@ backupStrategyController: - image: "ghcr.io/cozystack/cozystack/backupstrategy-controller:v1.1.0@sha256:508e3bd5a83a316732cfb84fe598064e3092482d941cfc53738ca21237642e6f" + image: "ghcr.io/cozystack/cozystack/backupstrategy-controller:v1.1.6@sha256:f33c928cbfeebf266e070da87980061ce7fcd7d29ca0322536ac7c49e09b3b97" replicas: 2 debug: false metrics: diff --git a/packages/system/bucket/images/s3manager.tag b/packages/system/bucket/images/s3manager.tag index b799967a..d3d5eb51 100644 --- a/packages/system/bucket/images/s3manager.tag +++ b/packages/system/bucket/images/s3manager.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/s3manager:v0.5.0@sha256:5a7cae722ff6b424bdfbc4aba9d072c11b6930e2ee0f5fa97c3a565bd1c8dc88 +ghcr.io/cozystack/cozystack/s3manager:v0.5.0@sha256:36235971fc1790b11d38210894cd24cae46a54d88445aa6c4821977c139a58f2 diff --git a/packages/system/bucket/templates/deployment.yaml b/packages/system/bucket/templates/deployment.yaml index 4e055334..5c13cb2d 100644 --- a/packages/system/bucket/templates/deployment.yaml +++ b/packages/system/bucket/templates/deployment.yaml @@ -1,3 +1,12 @@ +{{- $endpoint := printf "s3.%s" .Values._namespace.host }} +{{- range $name, $user := .Values.users }} + {{- $secretName := printf "%s-%s" $.Values.bucketName $name }} + {{- $existingSecret := lookup "v1" "Secret" $.Release.Namespace $secretName }} + {{- if $existingSecret }} + {{- $bucketInfo := fromJson (b64dec (index $existingSecret.data "BucketInfo")) }} + {{- $endpoint = trimPrefix "https://" (index $bucketInfo.spec.secretS3 "endpoint") }} + {{- end }} +{{- end }} apiVersion: apps/v1 kind: Deployment metadata: @@ -17,6 +26,6 @@ spec: image: "{{ $.Files.Get "images/s3manager.tag" | trim }}" env: - name: ENDPOINT - value: "s3.{{ .Values._namespace.host }}" + value: {{ $endpoint | quote }} - name: SKIP_SSL_VERIFICATION value: "true" diff --git a/packages/system/bucket/templates/ingress.yaml b/packages/system/bucket/templates/ingress.yaml index 6e5028fc..b7ffaf8b 100644 --- a/packages/system/bucket/templates/ingress.yaml +++ b/packages/system/bucket/templates/ingress.yaml @@ -12,7 +12,7 @@ metadata: nginx.ingress.kubernetes.io/proxy-read-timeout: "99999" nginx.ingress.kubernetes.io/proxy-send-timeout: "99999" {{- if eq $solver "http01" }} - acme.cert-manager.io/http01-ingress-class: {{ $ingress }} + acme.cert-manager.io/http01-ingress-ingressclassname: {{ $ingress }} {{- end }} cert-manager.io/cluster-issuer: {{ $clusterIssuer }} spec: diff --git a/packages/system/cert-manager-issuers/templates/cluster-issuers.yaml b/packages/system/cert-manager-issuers/templates/cluster-issuers.yaml index 442f1fb3..3b582082 100644 --- a/packages/system/cert-manager-issuers/templates/cluster-issuers.yaml +++ b/packages/system/cert-manager-issuers/templates/cluster-issuers.yaml @@ -1,6 +1,7 @@ {{- $solver := (index .Values._cluster "solver") | default "http01" }} +{{- $exposeIngress := (index .Values._cluster "expose-ingress") | default "tenant-root" }} -apiVersion: cert-manager.io/v1 +apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: letsencrypt-prod @@ -17,9 +18,9 @@ spec: name: cloudflare-api-token-secret key: api-token {{- else }} - http01: - ingress: - class: nginx + http01: + ingress: + ingressClassName: {{ $exposeIngress }} {{- end }} --- @@ -41,9 +42,9 @@ spec: name: cloudflare-api-token-secret key: api-token {{- else }} - http01: - ingress: - class: nginx + http01: + ingress: + ingressClassName: {{ $exposeIngress }} {{- end }} --- diff --git a/packages/system/cozystack-api/values.yaml b/packages/system/cozystack-api/values.yaml index dcd174c4..86513d34 100644 --- a/packages/system/cozystack-api/values.yaml +++ b/packages/system/cozystack-api/values.yaml @@ -1,3 +1,3 @@ cozystackAPI: - image: ghcr.io/cozystack/cozystack/cozystack-api:v1.1.0@sha256:3a8e559b1a71cffb445bab14178d9abeba1b90509f9fec31df5ff5a9a38333d1 + image: ghcr.io/cozystack/cozystack/cozystack-api:v1.1.6@sha256:82b8805ff5556fac11414f3bcd924d3aa12d57713ecedd2063b0bf9affef68b4 replicas: 2 diff --git a/packages/system/cozystack-basics/templates/clusterroles.yaml b/packages/system/cozystack-basics/templates/clusterroles.yaml index 72d924ef..f270f4e1 100644 --- a/packages/system/cozystack-basics/templates/clusterroles.yaml +++ b/packages/system/cozystack-basics/templates/clusterroles.yaml @@ -21,6 +21,9 @@ rules: - apiGroups: [""] resources: ["pods", "services", "persistentvolumes", "endpoints", "events", "resourcequotas"] verbs: ["get", "list", "watch"] +- apiGroups: ["discovery.k8s.io"] + resources: ["endpointslices"] + verbs: ["get", "list", "watch"] - apiGroups: ["networking.k8s.io"] resources: ["ingresses"] verbs: ["get", "list", "watch"] @@ -94,6 +97,14 @@ rules: - get - list - watch +- apiGroups: + - discovery.k8s.io + resources: + - endpointslices + verbs: + - get + - list + - watch - apiGroups: - networking.k8s.io resources: @@ -194,12 +205,18 @@ rules: - buckets - clickhouses - foos + - foundationdbs + - harbors - httpcaches - kafkas - kuberneteses - mariadbs + - mongodbs - natses + - openbaos + - opensearches - postgreses + - qdrants - rabbitmqs - redises - seaweedfses @@ -207,6 +224,7 @@ rules: - virtualmachines - vmdisks - vminstances + - vpns - infos - virtualprivateclouds verbs: diff --git a/packages/system/cozystack-controller/values.yaml b/packages/system/cozystack-controller/values.yaml index e01aa8be..6ce21a1c 100644 --- a/packages/system/cozystack-controller/values.yaml +++ b/packages/system/cozystack-controller/values.yaml @@ -1,4 +1,4 @@ cozystackController: - image: ghcr.io/cozystack/cozystack/cozystack-controller:v1.1.0@sha256:f04fa839924a761571e1035d83f380f39f62d1708ea8d22f7a323f17bb59ff96 + image: ghcr.io/cozystack/cozystack/cozystack-controller:v1.1.6@sha256:4627205f28aad46015cddd9e35a1e3a73911a1389371d28aaef9234854cdf19b debug: false disableTelemetry: false diff --git a/packages/system/dashboard/templates/configmap.yaml b/packages/system/dashboard/templates/configmap.yaml index 9a63c182..674a669d 100644 --- a/packages/system/dashboard/templates/configmap.yaml +++ b/packages/system/dashboard/templates/configmap.yaml @@ -1,6 +1,6 @@ {{- $brandingConfig := .Values._cluster.branding | default dict }} -{{- $tenantText := "v1.1.0" }} +{{- $tenantText := "v1.1.6" }} {{- $footerText := "Cozystack" }} {{- $titleText := "Cozystack Dashboard" }} {{- $logoText := "" }} diff --git a/packages/system/dashboard/templates/ingress.yaml b/packages/system/dashboard/templates/ingress.yaml index a10797fb..6cf01490 100644 --- a/packages/system/dashboard/templates/ingress.yaml +++ b/packages/system/dashboard/templates/ingress.yaml @@ -11,7 +11,7 @@ metadata: annotations: cert-manager.io/cluster-issuer: {{ $clusterIssuer }} {{- if eq $solver "http01" }} - acme.cert-manager.io/http01-ingress-class: {{ $exposeIngress }} + acme.cert-manager.io/http01-ingress-ingressclassname: {{ $exposeIngress }} {{- end }} nginx.ingress.kubernetes.io/rewrite-target: / nginx.ingress.kubernetes.io/client-max-body-size: 100m diff --git a/packages/system/dashboard/templates/keycloakclient.yaml b/packages/system/dashboard/templates/keycloakclient.yaml index d8e47e8a..1e0b5feb 100644 --- a/packages/system/dashboard/templates/keycloakclient.yaml +++ b/packages/system/dashboard/templates/keycloakclient.yaml @@ -49,6 +49,8 @@ apiVersion: v1.edp.epam.com/v1 kind: KeycloakClient metadata: name: dashboard-client + annotations: + secret-hash: {{ $dashboardClient | sha256sum }} spec: serviceAccount: enabled: true diff --git a/packages/system/dashboard/templates/rbac.yaml b/packages/system/dashboard/templates/rbac.yaml index 6dcb5da5..eb687a3e 100644 --- a/packages/system/dashboard/templates/rbac.yaml +++ b/packages/system/dashboard/templates/rbac.yaml @@ -20,6 +20,14 @@ rules: - get - list - watch +- apiGroups: + - storage.k8s.io + resources: + - storageclasses + verbs: + - get + - list + - watch --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding diff --git a/packages/system/dashboard/values.yaml b/packages/system/dashboard/values.yaml index d8550368..96ee59f2 100644 --- a/packages/system/dashboard/values.yaml +++ b/packages/system/dashboard/values.yaml @@ -1,6 +1,6 @@ openapiUI: - image: ghcr.io/cozystack/cozystack/openapi-ui:v1.1.0@sha256:bc530ae2e428727eed284d7f80b2eea4fdd98b7618d20cab262eef7199af5fa5 + image: ghcr.io/cozystack/cozystack/openapi-ui:v1.1.6@sha256:52e2a52375901dd5eeee443ccd8c9ee4c795f071344220c79e2225f07a9c2f4d openapiUIK8sBff: - image: ghcr.io/cozystack/cozystack/openapi-ui-k8s-bff:v1.1.0@sha256:c938fee904acd948800d4dc5e121c4c5cd64cb4a3160fb8d2f9dbff0e5168740 + image: ghcr.io/cozystack/cozystack/openapi-ui-k8s-bff:v1.1.6@sha256:0f508427bfa5a650eda6c5ef01ea32a586ac485a54902d7649ec49cc84f676f7 tokenProxy: - image: ghcr.io/cozystack/cozystack/token-proxy:v1.1.0@sha256:2e280991e07853ea48f97b0a42946afffa10d03d6a83d41099ed83e6ffc94fdc + image: ghcr.io/cozystack/cozystack/token-proxy:v1.1.6@sha256:2e280991e07853ea48f97b0a42946afffa10d03d6a83d41099ed83e6ffc94fdc diff --git a/packages/system/etcd-operator/charts/etcd-operator/README.md b/packages/system/etcd-operator/charts/etcd-operator/README.md index 144c2ef0..ff2e019a 100644 --- a/packages/system/etcd-operator/charts/etcd-operator/README.md +++ b/packages/system/etcd-operator/charts/etcd-operator/README.md @@ -38,8 +38,8 @@ | kubeRbacProxy.args[2] | string | `"--logtostderr=true"` | | | kubeRbacProxy.args[3] | string | `"--v=0"` | | | kubeRbacProxy.image.pullPolicy | string | `"IfNotPresent"` | Image pull policy | -| kubeRbacProxy.image.repository | string | `"gcr.io/kubebuilder/kube-rbac-proxy"` | Image repository | -| kubeRbacProxy.image.tag | string | `"v0.16.0"` | Version of image | +| kubeRbacProxy.image.repository | string | `"quay.io/brancz/kube-rbac-proxy"` | Image repository | +| kubeRbacProxy.image.tag | string | `"v0.18.1"` | Version of image | | kubeRbacProxy.livenessProbe | object | `{}` | https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/ | | kubeRbacProxy.readinessProbe | object | `{}` | https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/ | | kubeRbacProxy.resources | object | `{"limits":{"cpu":"250m","memory":"128Mi"},"requests":{"cpu":"100m","memory":"64Mi"}}` | ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ | diff --git a/packages/system/etcd-operator/charts/etcd-operator/values.yaml b/packages/system/etcd-operator/charts/etcd-operator/values.yaml index 9687a10c..b2b5cd4e 100644 --- a/packages/system/etcd-operator/charts/etcd-operator/values.yaml +++ b/packages/system/etcd-operator/charts/etcd-operator/values.yaml @@ -98,13 +98,13 @@ kubeRbacProxy: image: # -- Image repository - repository: gcr.io/kubebuilder/kube-rbac-proxy + repository: quay.io/brancz/kube-rbac-proxy # -- Image pull policy pullPolicy: IfNotPresent # -- Version of image - tag: v0.16.0 + tag: v0.18.1 args: - --secure-listen-address=0.0.0.0:8443 diff --git a/packages/system/grafana-operator/images/grafana-dashboards.tag b/packages/system/grafana-operator/images/grafana-dashboards.tag index 71332750..b775aa14 100644 --- a/packages/system/grafana-operator/images/grafana-dashboards.tag +++ b/packages/system/grafana-operator/images/grafana-dashboards.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/grafana-dashboards:v1.1.0@sha256:2c9aa0b48e2bf6167db198f4d15882bfe51700108edf2e9f6d0942940a2c1204 +ghcr.io/cozystack/cozystack/grafana-dashboards:v1.1.6@sha256:2c9aa0b48e2bf6167db198f4d15882bfe51700108edf2e9f6d0942940a2c1204 diff --git a/packages/system/kamaji/values.yaml b/packages/system/kamaji/values.yaml index 89227000..e5a630b6 100644 --- a/packages/system/kamaji/values.yaml +++ b/packages/system/kamaji/values.yaml @@ -3,7 +3,7 @@ kamaji: deploy: false image: pullPolicy: IfNotPresent - tag: v1.1.0@sha256:914d04f7442f0faecf18f8282c192dee9fe244a711494a8c892e2f9e2ad415f7 + tag: v1.1.6@sha256:a2ab1c507fb1b1249364823bd43bbf9db933009e66f110ca64cc933ce231d10c repository: ghcr.io/cozystack/cozystack/kamaji resources: limits: @@ -13,4 +13,4 @@ kamaji: cpu: 100m memory: 100Mi extraArgs: - - --migrate-image=ghcr.io/cozystack/cozystack/kamaji:v1.1.0@sha256:914d04f7442f0faecf18f8282c192dee9fe244a711494a8c892e2f9e2ad415f7 + - --migrate-image=ghcr.io/cozystack/cozystack/kamaji:v1.1.6@sha256:a2ab1c507fb1b1249364823bd43bbf9db933009e66f110ca64cc933ce231d10c diff --git a/packages/system/keycloak/templates/ingress.yaml b/packages/system/keycloak/templates/ingress.yaml index aa282f71..7f9fd476 100644 --- a/packages/system/keycloak/templates/ingress.yaml +++ b/packages/system/keycloak/templates/ingress.yaml @@ -11,7 +11,7 @@ metadata: {{- with .Values.ingress.annotations }} annotations: {{- if eq $solver "http01" }} - acme.cert-manager.io/http01-ingress-class: {{ $exposeIngress }} + acme.cert-manager.io/http01-ingress-ingressclassname: {{ $exposeIngress }} {{- end }} cert-manager.io/cluster-issuer: {{ $clusterIssuer }} {{- toYaml . | nindent 4 }} diff --git a/packages/system/keycloak/templates/sts.yaml b/packages/system/keycloak/templates/sts.yaml index c7506f8f..e2bba431 100644 --- a/packages/system/keycloak/templates/sts.yaml +++ b/packages/system/keycloak/templates/sts.yaml @@ -76,6 +76,8 @@ spec: {{- end }} - name: KC_METRICS_ENABLED value: "true" + - name: KC_HEALTH_ENABLED + value: "true" - name: KC_LOG_LEVEL value: "info" - name: KC_CACHE @@ -130,16 +132,27 @@ spec: - name: http containerPort: 8080 protocol: TCP + - name: management + containerPort: 9000 + protocol: TCP + startupProbe: + httpGet: + path: /health/ready + port: management + failureThreshold: 30 + periodSeconds: 10 livenessProbe: httpGet: - path: / - port: http - initialDelaySeconds: 120 + path: /health/live + port: management + periodSeconds: 15 timeoutSeconds: 5 + failureThreshold: 5 readinessProbe: httpGet: - path: /realms/master - port: http - initialDelaySeconds: 60 - timeoutSeconds: 1 + path: /health/ready + port: management + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 3 terminationGracePeriodSeconds: 60 diff --git a/packages/system/kubeovn-plunger/values.yaml b/packages/system/kubeovn-plunger/values.yaml index 7f22578d..cf0cdb37 100644 --- a/packages/system/kubeovn-plunger/values.yaml +++ b/packages/system/kubeovn-plunger/values.yaml @@ -1,4 +1,4 @@ portSecurity: true routes: "" -image: ghcr.io/cozystack/cozystack/kubeovn-plunger:v1.1.0@sha256:b91bf0964a3204e50f703092f190b7d96c078a6ccee430215042ae1275ed5127 +image: ghcr.io/cozystack/cozystack/kubeovn-plunger:v1.1.6@sha256:5dfd61d60e915ea92157fb84dc861c811b02775b9bbd4343e1093d866f2bf83b ovnCentralName: ovn-central diff --git a/packages/system/kubeovn-webhook/values.yaml b/packages/system/kubeovn-webhook/values.yaml index c2fe2c6f..faea2c21 100644 --- a/packages/system/kubeovn-webhook/values.yaml +++ b/packages/system/kubeovn-webhook/values.yaml @@ -1,3 +1,3 @@ portSecurity: true routes: "" -image: ghcr.io/cozystack/cozystack/kubeovn-webhook:v1.1.0@sha256:e18f9fd679e38f65362a8d0042f25468272f6d081136ad47027168d8e7e07a4a +image: ghcr.io/cozystack/cozystack/kubeovn-webhook:v1.1.6@sha256:e18f9fd679e38f65362a8d0042f25468272f6d081136ad47027168d8e7e07a4a diff --git a/packages/system/kubevirt-csi-node/values.yaml b/packages/system/kubevirt-csi-node/values.yaml index 439edef4..01783389 100644 --- a/packages/system/kubevirt-csi-node/values.yaml +++ b/packages/system/kubevirt-csi-node/values.yaml @@ -1,3 +1,3 @@ storageClass: replicated csiDriver: - image: ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.0.0@sha256:faaa6bcdb68196edb4baafe643679bd7d2ef35f910c639b71e06a4ecc034f232 + image: ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.0.0@sha256:7932ffb1dbb7334564018811d6ea2e73dd05cc203e3d807c92bb5630ea1488cf diff --git a/packages/system/lineage-controller-webhook/values.yaml b/packages/system/lineage-controller-webhook/values.yaml index f4d62e1c..38dc982f 100644 --- a/packages/system/lineage-controller-webhook/values.yaml +++ b/packages/system/lineage-controller-webhook/values.yaml @@ -1,5 +1,5 @@ lineageControllerWebhook: - image: ghcr.io/cozystack/cozystack/lineage-controller-webhook:v1.1.0@sha256:4d6a2bb76cae84e24cd48c7377b03ed6bdfefe611221d2c0a7f77a5457db8849 + image: ghcr.io/cozystack/cozystack/lineage-controller-webhook:v1.1.6@sha256:392ff9f36e01a92cfe7c9686b7b31707a291caa9723889093676b43daca90a65 debug: false localK8sAPIEndpoint: enabled: true diff --git a/packages/system/linstor/images/piraeus-server/Dockerfile b/packages/system/linstor/images/piraeus-server/Dockerfile index 049a3f47..f93e494f 100644 --- a/packages/system/linstor/images/piraeus-server/Dockerfile +++ b/packages/system/linstor/images/piraeus-server/Dockerfile @@ -61,6 +61,8 @@ RUN test -d .gradlehome && echo ".gradlehome found in tarball" || (echo ".gradle # Build DEB packages from tarball # Override GRADLE_FLAGS to remove --offline flag, allowing Gradle to download missing dependencies RUN sed -i 's/GRADLE_FLAGS = --offline/GRADLE_FLAGS =/' debian/rules || true +# Skip dh_strip_nondeterminism to avoid failures on some JAR files (logback-core) +RUN printf '\noverride_dh_strip_nondeterminism:\n\ttrue\n' >> debian/rules RUN LD_LIBRARY_PATH='' dpkg-buildpackage -rfakeroot -b -uc # Copy built .deb packages to a location accessible from final image diff --git a/packages/system/linstor/images/piraeus-server/patches/README.md b/packages/system/linstor/images/piraeus-server/patches/README.md index 5ee29318..558fdfeb 100644 --- a/packages/system/linstor/images/piraeus-server/patches/README.md +++ b/packages/system/linstor/images/piraeus-server/patches/README.md @@ -8,7 +8,7 @@ Custom patches for piraeus-server (linstor-server) v1.32.3. - Upstream: [#475](https://github.com/LINBIT/linstor-server/pull/475) - **force-metadata-check-on-disk-add.diff** — Create metadata during toggle-disk from diskless to diskful - Upstream: [#474](https://github.com/LINBIT/linstor-server/pull/474) -- **fix-duplicate-tcp-ports.diff** — Prevent duplicate TCP ports after toggle-disk operations - - Upstream: [#476](https://github.com/LINBIT/linstor-server/pull/476) +- **fix-duplicate-tcp-ports.diff** — Preserve TCP ports during toggle-disk to prevent port mismatch between controller and satellites + - Upstream: [#476](https://github.com/LINBIT/linstor-server/pull/476) (superseded by this expanded fix) - **skip-adjust-when-device-inaccessible.diff** — Fix resources stuck in StandAlone after reboot, Unknown state race condition, and encrypted resource deletion - Upstream: [#477](https://github.com/LINBIT/linstor-server/pull/477) diff --git a/packages/system/linstor/images/piraeus-server/patches/fix-duplicate-tcp-ports.diff b/packages/system/linstor/images/piraeus-server/patches/fix-duplicate-tcp-ports.diff index 07cd9eac..b34a2500 100644 --- a/packages/system/linstor/images/piraeus-server/patches/fix-duplicate-tcp-ports.diff +++ b/packages/system/linstor/images/piraeus-server/patches/fix-duplicate-tcp-ports.diff @@ -1,80 +1,131 @@ -From 1250abe99d64a0501795e37d3b6af62410002239 Mon Sep 17 00:00:00 2001 +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil -Date: Mon, 12 Jan 2026 13:44:46 +0100 -Subject: [PATCH] fix(drbd): prevent duplicate TCP ports after toggle-disk - operations +Date: Fri, 28 Mar 2026 13:00:00 +0100 +Subject: [PATCH] fix(drbd): preserve TCP ports during toggle-disk operations -Remove redundant ensureStackDataExists() call with empty payload from -resetStoragePools() method that was causing TCP port conflicts after -toggle-disk operations. +Prevent TCP port mismatches after toggle-disk operations by preserving +existing TCP ports when rebuilding DrbdRscData. Root Cause: ----------- -The resetStoragePools() method, introduced in 2019 (commit 95cc17d0b8), -calls ensureStackDataExists() with an empty LayerPayload. This worked -correctly when TCP ports were stored at RscDfn level. +During toggle-disk operations, removeLayerData() deletes DrbdRscData +(freeing its TCP ports from the number pool), then ensureStackDataExists() +creates new DrbdRscData. Since the payload has no explicit tcpPorts, +the controller allocates new ports from the pool -- which may differ from +the old ports if other resources claimed them in the meantime. -After the TCP port migration to per-node level (commit f754943463, May -2025), this empty payload results in DrbdRscData being created without -TCP ports assigned. The controller then sends a Pojo with an empty port -Set to satellites. +The controller correctly avoids collisions in its own number pool, but +the satellite may miss the update (e.g. during controller restart or +network issues). When this happens, the satellite keeps the old ports +while peers receive the new ones, causing DRBD connection failures +(StandAlone/Connecting state). -On satellites, when DrbdRscData is initialized with an empty port list, -initPorts() uses preferredNewPortsRef from peer resources. Since -SatelliteDynamicNumberPool.tryAllocate() always returns true (no-op), -any port from preferredNewPortsRef is accepted without conflict checking, -leading to duplicate TCP port assignments. - -Impact: -------- -This regression affects toggle-disk operations, particularly: -- Snapshot creation/restore operations -- Manual toggle-disk operations -- Any operation calling resetStoragePools() - -Symptoms include: -- DRBD resources failing to adjust with "port is also used" errors -- Resources stuck in StandAlone or Connecting states -- Multiple resources on the same node using identical TCP ports +Additionally, remove the redundant ensureStackDataExists() call from +resetStoragePools() -- the caller already invokes it with the correct +payload. Solution: --------- -Remove the ensureStackDataExists() call from resetStoragePools() as it -is redundant. The calling code (e.g., CtrlRscToggleDiskApiCallHandler -line 1071) already invokes ensureStackDataExists() with the correct -payload immediately after resetStoragePools(). +1. Add copyDrbdTcpPortsIfExists() to save existing TCP ports into the + LayerPayload before removeLayerData() deletes them. +2. Call it from copyDrbdNodeIdIfExists() (covers both toggle-disk paths) + and from the needsDeactivate path (shared storage pool case). +3. Remove the redundant ensureStackDataExists() from resetStoragePools(). -This fix ensures: -1. resetStoragePools() only resets storage pool assignments -2. Layer data creation with proper TCP ports happens via the caller's - ensureStackDataExists() with correct payload -3. No DrbdRscData objects are created without TCP port assignments - -Related Issues: ---------------- -Fixes #454 - Duplicate TCP ports after backup/restore operations -Related to user reports of resources stuck in StandAlone after node -reboots when toggle-disk or backup operations were in progress. - -Testing: --------- -Verified that: -- Toggle-disk operations no longer create resources without TCP ports -- Backup/restore operations complete without TCP port conflicts -- Resources maintain unique TCP ports across toggle-disk cycles +This ensures the same TCP ports are reused when DrbdRscData is recreated, +eliminating the window for port mismatch between controller and satellites. Co-Authored-By: Claude Signed-off-by: Andrei Kvapil --- - .../linbit/linstor/layer/resource/CtrlRscLayerDataFactory.java | 2 -- - 1 file changed, 2 deletions(-) + .../controller/CtrlRscToggleDiskApiCallHandler.java | 40 +++++++++++++++++++-- + .../linstor/layer/resource/CtrlRscLayerDataFactory.java | 2 -- + 2 files changed, 38 insertions(+), 4 deletions(-) +diff --git a/controller/src/main/java/com/linbit/linstor/core/apicallhandler/controller/CtrlRscToggleDiskApiCallHandler.java b/controller/src/main/java/com/linbit/linstor/core/apicallhandler/controller/CtrlRscToggleDiskApiCallHandler.java +index ccdb0cee5..b0554c2ec 100644 +--- a/controller/src/main/java/com/linbit/linstor/core/apicallhandler/controller/CtrlRscToggleDiskApiCallHandler.java ++++ b/controller/src/main/java/com/linbit/linstor/core/apicallhandler/controller/CtrlRscToggleDiskApiCallHandler.java +@@ -58,6 +58,7 @@ import com.linbit.linstor.stateflags.StateFlags; + import com.linbit.linstor.storage.StorageException; + import com.linbit.linstor.storage.data.adapter.drbd.DrbdRscData; + import com.linbit.linstor.storage.interfaces.categories.resource.AbsRscLayerObject; ++import com.linbit.linstor.core.types.TcpPortNumber; + import com.linbit.linstor.storage.interfaces.categories.resource.VlmProviderObject; + import com.linbit.linstor.storage.kinds.DeviceLayerKind; + import com.linbit.linstor.storage.kinds.DeviceProviderKind; +@@ -88,6 +89,7 @@ import java.util.LinkedHashMap; + import java.util.List; + import java.util.Map.Entry; + import java.util.Set; ++import java.util.TreeSet; + + import org.reactivestreams.Publisher; + import reactor.core.publisher.Flux; +@@ -587,8 +589,9 @@ public class CtrlRscToggleDiskApiCallHandler implements CtrlSatelliteConnectionL + + /* + * We also have to remove the currently diskless DrbdRscData and free up the node-id as now we must +- * use the shared resource's node-id ++ * use the shared resource's node-id. We still need to preserve TCP ports though. + */ ++ copyDrbdTcpPortsIfExists(rsc, payload); + } + else + { +@@ -726,7 +729,7 @@ public class CtrlRscToggleDiskApiCallHandler implements CtrlSatelliteConnectionL + /** + * Although we need to rebuild the layerData as the layerList might have changed, if we do not + * deactivate (i.e. down) the current resource, we need to make sure that deleting DrbdRscData +- * and recreating a new DrbdRscData ends up with the same node-id as before. ++ * and recreating a new DrbdRscData ends up with the same node-id and TCP ports as before. + */ + private void copyDrbdNodeIdIfExists(Resource rsc, LayerPayload payload) throws ImplementationError + { +@@ -743,6 +746,37 @@ public class CtrlRscToggleDiskApiCallHandler implements CtrlSatelliteConnectionL + DrbdRscData drbdRscData = (DrbdRscData) drbdRscDataSet.iterator().next(); + payload.drbdRsc.nodeId = drbdRscData.getNodeId().value; + } ++ copyDrbdTcpPortsIfExists(rsc, payload); ++ } ++ ++ /** ++ * Preserves existing TCP ports during toggle-disk operations. ++ * ++ * When removeLayerData() deletes DrbdRscData, the TCP ports are freed from the number pool. ++ * If ensureStackDataExists() then allocates different ports, and the satellite misses the update ++ * (e.g. due to controller restart or connectivity issues), the satellite keeps the old ports ++ * while peers get the new ones, causing DRBD connections to fail with StandAlone state. ++ */ ++ private void copyDrbdTcpPortsIfExists(Resource rsc, LayerPayload payload) throws ImplementationError ++ { ++ Set> drbdRscDataSet = LayerRscUtils.getRscDataByLayer( ++ getLayerData(apiCtx, rsc), ++ DeviceLayerKind.DRBD ++ ); ++ if (!drbdRscDataSet.isEmpty()) ++ { ++ DrbdRscData drbdRscData = (DrbdRscData) drbdRscDataSet.iterator().next(); ++ Collection tcpPorts = drbdRscData.getTcpPortList(); ++ if (tcpPorts != null && !tcpPorts.isEmpty()) ++ { ++ Set portInts = new TreeSet<>(); ++ for (TcpPortNumber port : tcpPorts) ++ { ++ portInts.add(port.value); ++ } ++ payload.drbdRsc.tcpPorts = portInts; ++ } ++ } + } + + private List removeLayerData(Resource rscRef) diff --git a/controller/src/main/java/com/linbit/linstor/layer/resource/CtrlRscLayerDataFactory.java b/controller/src/main/java/com/linbit/linstor/layer/resource/CtrlRscLayerDataFactory.java index 3538b380c..4f589145e 100644 --- a/controller/src/main/java/com/linbit/linstor/layer/resource/CtrlRscLayerDataFactory.java +++ b/controller/src/main/java/com/linbit/linstor/layer/resource/CtrlRscLayerDataFactory.java @@ -276,8 +276,6 @@ public class CtrlRscLayerDataFactory - + rscDataToProcess.addAll(rscData.getChildren()); } - @@ -82,6 +133,6 @@ index 3538b380c..4f589145e 100644 } catch (AccessDeniedException exc) { --- +-- 2.39.5 (Apple Git-154) diff --git a/packages/system/linstor/templates/podscrape.yaml b/packages/system/linstor/templates/podscrape.yaml index 786bc687..05b1483e 100644 --- a/packages/system/linstor/templates/podscrape.yaml +++ b/packages/system/linstor/templates/podscrape.yaml @@ -11,7 +11,7 @@ spec: relabelConfigs: - action: labeldrop regex: (endpoint|namespace|pod|container) - - replacement: linstor-controller + - replacement: linstor-satellite targetLabel: job - sourceLabels: [__meta_kubernetes_pod_node_name] targetLabel: node @@ -34,7 +34,7 @@ spec: relabelConfigs: - action: labeldrop regex: (endpoint|namespace|pod|container) - - replacement: linstor-satellite + - replacement: linstor-controller targetLabel: job - sourceLabels: [__meta_kubernetes_pod_node_name] targetLabel: controller_node diff --git a/packages/system/linstor/values.yaml b/packages/system/linstor/values.yaml index bcf530b3..311f58f7 100644 --- a/packages/system/linstor/values.yaml +++ b/packages/system/linstor/values.yaml @@ -1,7 +1,7 @@ piraeusServer: image: repository: ghcr.io/cozystack/cozystack/piraeus-server - tag: 1.32.3@sha256:aa97f39d90c0726b587f0a376504f13d1f308adeb42db7d98cec9ac7de237361 + tag: 1.32.3@sha256:0e9e0aed933dd5671e5c7c0b5342df98f11615faa39c89655e6c43f181ac5dc4 # Talos-specific workarounds (disable for generic Linux like Ubuntu/Debian) talos: enabled: true @@ -13,4 +13,4 @@ linstor: linstorCSI: image: repository: ghcr.io/cozystack/cozystack/linstor-csi - tag: v1.10.5@sha256:50ab1ab0210d4e7ebfca311f445bb764516db5ddb63fc6d28536b28622eee753 + tag: v1.10.5@sha256:e153fe83a22b20c7201e8ad472c12eee72d8fbc7244bb39ba5eaec825334ae43 diff --git a/packages/system/monitoring/templates/alerta/alerta.yaml b/packages/system/monitoring/templates/alerta/alerta.yaml index d727d5e6..11aa417e 100644 --- a/packages/system/monitoring/templates/alerta/alerta.yaml +++ b/packages/system/monitoring/templates/alerta/alerta.yaml @@ -173,7 +173,7 @@ metadata: app: alerta annotations: {{- if eq $solver "http01" }} - acme.cert-manager.io/http01-ingress-class: {{ $ingress }} + acme.cert-manager.io/http01-ingress-ingressclassname: {{ $ingress }} {{- end }} cert-manager.io/cluster-issuer: {{ $clusterIssuer }} spec: diff --git a/packages/system/monitoring/templates/grafana/grafana.yaml b/packages/system/monitoring/templates/grafana/grafana.yaml index d7f51e31..d65a7dc4 100644 --- a/packages/system/monitoring/templates/grafana/grafana.yaml +++ b/packages/system/monitoring/templates/grafana/grafana.yaml @@ -74,7 +74,7 @@ spec: metadata: annotations: {{- if eq $solver "http01" }} - acme.cert-manager.io/http01-ingress-class: "{{ $ingress }}" + acme.cert-manager.io/http01-ingress-ingressclassname: "{{ $ingress }}" {{- end }} cert-manager.io/cluster-issuer: {{ $clusterIssuer }} spec: diff --git a/packages/system/objectstorage-controller/values.yaml b/packages/system/objectstorage-controller/values.yaml index 2145657c..aa9c1760 100644 --- a/packages/system/objectstorage-controller/values.yaml +++ b/packages/system/objectstorage-controller/values.yaml @@ -1,3 +1,3 @@ objectstorage: controller: - image: "ghcr.io/cozystack/cozystack/objectstorage-controller:v1.1.0@sha256:e40e94f3014cfd04cce4230597315a1acfcca2daa8051b987614d0c05da6d928" + image: "ghcr.io/cozystack/cozystack/objectstorage-controller:v1.1.6@sha256:80b021df9137b45d9ba99d6fa1ffaaa1bb456d129df1666f12b838806d50095c" diff --git a/packages/system/piraeus-operator/alerts/piraeus-datastore.yaml b/packages/system/piraeus-operator/alerts/piraeus-datastore.yaml index 77512847..0cc39fe8 100644 --- a/packages/system/piraeus-operator/alerts/piraeus-datastore.yaml +++ b/packages/system/piraeus-operator/alerts/piraeus-datastore.yaml @@ -7,19 +7,31 @@ spec: groups: - name: linstor.rules rules: - - alert: linstorControllerOffline + - alert: linstorControllerUnavailable annotations: description: | - LINSTOR Controller is not reachable. - expr: up{job="linstor-controller"} == 0 + LINSTOR Controller deployment has no available replicas. + expr: kube_deployment_status_replicas_available{namespace="cozy-linstor",deployment="linstor-controller"} < 1 + for: 3m labels: severity: critical + - alert: linstorControllerMetricsScrapeFailing + annotations: + description: | + LINSTOR Controller metrics endpoint is not being scraped successfully. + expr: up{job="linstor-controller"} == 0 + for: 10m + labels: + severity: warning - alert: linstorSatelliteErrorRate annotations: description: | - LINSTOR Satellite "{{ $labels.name }}" reports {{ $value }} errors in the last 15 minutes. - Use "linstor error-reports list --nodes {{ $labels.name }} --since 15minutes" to see them. - expr: increase(linstor_error_reports_count{module="SATELLITE"}[15m]) > 0 + LINSTOR Satellite "{{ $labels.hostname }}" reports {{ $value }} errors in the last 15 minutes. + Use "linstor error-reports list --nodes {{ $labels.hostname }}" to inspect the reports. + expr: | + increase(linstor_error_reports_count{module="SATELLITE"}[15m]) > 0 + and on(instance, job) + min_over_time(up{job="linstor-controller"}[15m]) == 1 labels: severity: warning - alert: linstorControllerErrorRate @@ -33,7 +45,7 @@ spec: - alert: linstorSatelliteNotOnline annotations: description: | - LINSTOR Satellite "{{ $labels.name }}" is not ONLINE. + LINSTOR Satellite "{{ $labels.hostname }}" is not ONLINE. Check that the Satellite is running and reachable from the LINSTOR Controller. expr: linstor_node_state{nodetype="SATELLITE"} != 2 labels: diff --git a/packages/system/seaweedfs/values.yaml b/packages/system/seaweedfs/values.yaml index 5fea4a0d..3ffb4a42 100644 --- a/packages/system/seaweedfs/values.yaml +++ b/packages/system/seaweedfs/values.yaml @@ -111,7 +111,7 @@ seaweedfs: nginx.ingress.kubernetes.io/client-body-timeout: "3600" nginx.ingress.kubernetes.io/client-header-timeout: "120" nginx.ingress.kubernetes.io/service-upstream: "true" - acme.cert-manager.io/http01-ingress-class: tenant-root + acme.cert-manager.io/http01-ingress-ingressclassname: tenant-root cert-manager.io/cluster-issuer: letsencrypt-prod tls: - hosts: @@ -177,7 +177,7 @@ seaweedfs: bucketClassName: "seaweedfs" region: "" sidecar: - image: "ghcr.io/cozystack/cozystack/objectstorage-sidecar:v1.1.0@sha256:2a3595cd88b30af55b2000d3ca204899beecef0012b0e0402754c3914aad1f7f" + image: "ghcr.io/cozystack/cozystack/objectstorage-sidecar:v1.1.6@sha256:37036d667afc0f2d469242364dbd718478ba416f1d728f0dd8407ea9c940155a" certificates: commonName: "SeaweedFS CA" ipAddresses: [] diff --git a/pkg/cmd/server/openapi.go b/pkg/cmd/server/openapi.go index 616709ca..5d1b35db 100644 --- a/pkg/cmd/server/openapi.go +++ b/pkg/cmd/server/openapi.go @@ -224,8 +224,8 @@ func buildPostProcessV3(kindSchemas map[string]string) func(*spec3.OpenAPI) (*sp base, ok1 := doc.Components.Schemas[baseRef] list, ok2 := doc.Components.Schemas[baseListRef] stat, ok3 := doc.Components.Schemas[baseStatusRef] - if !(ok1 && ok2 && ok3) && len(kindSchemas) > 0 { - return doc, fmt.Errorf("base Application* schemas not found") + if !(ok1 && ok2 && ok3) { + return doc, nil // not the apps GV — nothing to patch } // Clone base schemas for each kind @@ -339,8 +339,8 @@ func buildPostProcessV2(kindSchemas map[string]string) func(*spec.Swagger) (*spe base, ok1 := defs[baseRef] list, ok2 := defs[baseListRef] stat, ok3 := defs[baseStatusRef] - if !(ok1 && ok2 && ok3) && len(kindSchemas) > 0 { - return sw, fmt.Errorf("base Application* schemas not found") + if !(ok1 && ok2 && ok3) { + return sw, nil // not the apps GV — nothing to patch } for kind, raw := range kindSchemas {