From ef373c91cd8d13da635028a0a57778dada913492 Mon Sep 17 00:00:00 2001 From: "v.oleynikov" Date: Sun, 28 Jun 2026 16:00:36 +0300 Subject: [PATCH 1/5] ci: translate cyrillic comment in translate-changelog workflow to fix no-cyrillic lint The `dmt lint` no-cyrillic linter flagged a Cyrillic comment in .github/workflows/translate-changelog.yml as a critical error, failing the build_dev / Lint check. Translate the comment to English. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/translate-changelog.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/translate-changelog.yml b/.github/workflows/translate-changelog.yml index f0d590a..636a321 100644 --- a/.github/workflows/translate-changelog.yml +++ b/.github/workflows/translate-changelog.yml @@ -2,7 +2,7 @@ name: Translate Changelog and Create PR on: push: - # Запуск для всех веток при любом push + # Run on every push to any branch jobs: translate-and-pr: From 75deccf5b55c51872e5e3f99e7dc616b3e0fc0d2 Mon Sep 17 00:00:00 2001 From: "v.oleynikov" Date: Sun, 28 Jun 2026 16:05:24 +0300 Subject: [PATCH 2/5] fix(controller): drop invariant readyType param to fix unparam lint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Go linter (golangci-lint / unparam) flagged three params that always receive the same value: - garage/resources_test.go: the `cluster` test helper's ClusterType param always got Lightweight — drop it and set the type inside. - controller/shared.go: advance() and aggregateReady() took a readyType param that always resolved to "Ready" (both v1alpha1.OSCConditionReady and OBConditionReady equal "Ready"). The aggregate Ready condition type is a single invariant, so introduce a package-level conditionReady constant and drop the param from advance/gateAfter/aggregateReady and their callers. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../internal/backend/garage/resources_test.go | 16 ++++++------ .../controller/object_bucket_controller.go | 12 ++++----- .../object_storage_cluster_controller.go | 8 +++--- .../controller/internal/controller/shared.go | 25 +++++++++++-------- .../internal/controller/shared_test.go | 10 ++++---- 5 files changed, 38 insertions(+), 33 deletions(-) diff --git a/images/controller/internal/backend/garage/resources_test.go b/images/controller/internal/backend/garage/resources_test.go index 4c8ec16..f2325f7 100644 --- a/images/controller/internal/backend/garage/resources_test.go +++ b/images/controller/internal/backend/garage/resources_test.go @@ -26,10 +26,10 @@ import ( v1alpha1 "github.com/deckhouse/sds-object/api/v1alpha1" ) -func cluster(name string, t v1alpha1.ClusterType, r v1alpha1.RedundancyMode) *v1alpha1.ObjectStorageCluster { +func cluster(name string, r v1alpha1.RedundancyMode) *v1alpha1.ObjectStorageCluster { return &v1alpha1.ObjectStorageCluster{ ObjectMeta: metav1.ObjectMeta{Name: name}, - Spec: v1alpha1.ObjectStorageClusterSpec{Type: t, Redundancy: r}, + Spec: v1alpha1.ObjectStorageClusterSpec{Type: v1alpha1.ClusterTypeLightweight, Redundancy: r}, } } @@ -41,25 +41,25 @@ func TestReplicationFactor(t *testing.T) { v1alpha1.RedundancyMode(""): 3, // default } for r, want := range cases { - if got := replicationFactor(cluster("c", v1alpha1.ClusterTypeLightweight, r)); got != want { + if got := replicationFactor(cluster("c", r)); got != want { t.Errorf("replicationFactor(%q)=%d, want %d", r, got, want) } } } func TestStorageSize(t *testing.T) { - none := cluster("c", v1alpha1.ClusterTypeLightweight, "") + none := cluster("c", "") if got := storageSize(none); got.Cmp(resource.MustParse("10Gi")) != 0 { t.Errorf("storageSize(unset)=%s, want 10Gi", got.String()) } - sized := cluster("c", v1alpha1.ClusterTypeLightweight, "") + sized := cluster("c", "") sized.Spec.Storage = &v1alpha1.ObjectStorageClusterStorageSpec{Size: "20Gi"} if got := storageSize(sized); got.Cmp(resource.MustParse("20Gi")) != 0 { t.Errorf("storageSize(20Gi)=%s, want 20Gi", got.String()) } - bad := cluster("c", v1alpha1.ClusterTypeLightweight, "") + bad := cluster("c", "") bad.Spec.Storage = &v1alpha1.ObjectStorageClusterStorageSpec{Size: "not-a-quantity"} if got := storageSize(bad); got.Cmp(resource.MustParse("10Gi")) != 0 { t.Errorf("storageSize(invalid)=%s, want 10Gi fallback", got.String()) @@ -67,7 +67,7 @@ func TestStorageSize(t *testing.T) { } func TestRenderConfig(t *testing.T) { - cfg := renderConfig(cluster("c", v1alpha1.ClusterTypeLightweight, v1alpha1.RedundancyHighRedundancy)) + cfg := renderConfig(cluster("c", v1alpha1.RedundancyHighRedundancy)) for _, want := range []string{ "replication_factor = 5", "[s3_api]", @@ -81,7 +81,7 @@ func TestRenderConfig(t *testing.T) { } func TestNamesAndEndpoints(t *testing.T) { - c := cluster("shared", v1alpha1.ClusterTypeLightweight, "") + c := cluster("shared", "") if got := resourceName(c); got != "shared-garage" { t.Errorf("resourceName=%q", got) } diff --git a/images/controller/internal/controller/object_bucket_controller.go b/images/controller/internal/controller/object_bucket_controller.go index e28b685..3846e59 100644 --- a/images/controller/internal/controller/object_bucket_controller.go +++ b/images/controller/internal/controller/object_bucket_controller.go @@ -207,7 +207,7 @@ func (r *ObjectBucketReconciler) reconcileNormal(ctx context.Context, bucket *v1 if err != nil { status.setCondition(v1alpha1.OBConditionBucketReady, metav1.ConditionFalse, "WaitingForCluster", fmt.Sprintf("ObjectStorageCluster %q is not available: %v", bucket.Spec.ClusterRef, err)) - gateAfter(status, obStageOrder, v1alpha1.OBConditionReady, v1alpha1.OBConditionBucketReady) + gateAfter(status, obStageOrder, v1alpha1.OBConditionBucketReady) return r.finish(ctx, bucket, status, observed, nil) } if cluster.Status != nil && cluster.Status.Endpoint != nil { @@ -216,26 +216,26 @@ func (r *ObjectBucketReconciler) reconcileNormal(ctx context.Context, bucket *v1 if clusterReadyState(cluster) != string(metav1.ConditionTrue) { status.setCondition(v1alpha1.OBConditionBucketReady, metav1.ConditionFalse, "WaitingForCluster", fmt.Sprintf("ObjectStorageCluster %q is not Ready", bucket.Spec.ClusterRef)) - gateAfter(status, obStageOrder, v1alpha1.OBConditionReady, v1alpha1.OBConditionBucketReady) + gateAfter(status, obStageOrder, v1alpha1.OBConditionBucketReady) return r.finish(ctx, bucket, status, observed, nil) } driver, err := r.Registry.For(cluster) if err != nil { status.setCondition(v1alpha1.OBConditionBucketReady, metav1.ConditionFalse, reasonError, err.Error()) - gateAfter(status, obStageOrder, v1alpha1.OBConditionReady, v1alpha1.OBConditionBucketReady) + gateAfter(status, obStageOrder, v1alpha1.OBConditionBucketReady) return r.finish(ctx, bucket, status, observed, err) } state, err := driver.EnsureBucket(ctx, cluster, bucket) observed.bucketName = state.BucketName - if !advance(status, obStageOrder, v1alpha1.OBConditionReady, v1alpha1.OBConditionBucketReady, state.Ready, state.Message, err) { + if !advance(status, obStageOrder, v1alpha1.OBConditionBucketReady, state.Ready, state.Message, err) { return r.finish(ctx, bucket, status, observed, err) } // Stage 2: CredentialsReady — (re)write the credentials Secret. secretName, err := r.ensureCredentialsSecret(ctx, cluster, bucket, &state) - if !advance(status, obStageOrder, v1alpha1.OBConditionReady, v1alpha1.OBConditionCredentialsReady, err == nil, + if !advance(status, obStageOrder, v1alpha1.OBConditionCredentialsReady, err == nil, "credentials Secret written", err) { return r.finish(ctx, bucket, status, observed, err) } @@ -321,7 +321,7 @@ func (r *ObjectBucketReconciler) finish( if reconcileErr != nil { return ctrl.Result{}, reconcileErr } - if aggregateReady(status, v1alpha1.OBConditionReady) { + if aggregateReady(status) { return ctrl.Result{}, nil } return ctrl.Result{RequeueAfter: r.Cfg.RequeueInterval}, nil diff --git a/images/controller/internal/controller/object_storage_cluster_controller.go b/images/controller/internal/controller/object_storage_cluster_controller.go index d50645e..6b183d1 100644 --- a/images/controller/internal/controller/object_storage_cluster_controller.go +++ b/images/controller/internal/controller/object_storage_cluster_controller.go @@ -135,12 +135,12 @@ func (r *ObjectStorageClusterReconciler) reconcileNormal(ctx context.Context, cl if err != nil { // No driver for this profile is a terminal configuration error. status.setCondition(v1alpha1.OSCConditionBackendReady, metav1.ConditionFalse, reasonError, err.Error()) - gateAfter(status, oscStageOrder, v1alpha1.OSCConditionReady, v1alpha1.OSCConditionBackendReady) + gateAfter(status, oscStageOrder, v1alpha1.OSCConditionBackendReady) return r.finish(ctx, cluster, status, nil, err) } state, err := driver.EnsureCluster(ctx, cluster) - if !advance(status, oscStageOrder, v1alpha1.OSCConditionReady, v1alpha1.OSCConditionBackendReady, state.Ready, state.Message, err) { + if !advance(status, oscStageOrder, v1alpha1.OSCConditionBackendReady, state.Ready, state.Message, err) { return r.finish(ctx, cluster, status, &state, err) } @@ -149,7 +149,7 @@ func (r *ObjectStorageClusterReconciler) reconcileNormal(ctx context.Context, cl if !endpointReady { endpointMsg = "waiting for the backend to publish an S3 endpoint" } - if !advance(status, oscStageOrder, v1alpha1.OSCConditionReady, v1alpha1.OSCConditionEndpointReady, endpointReady, endpointMsg, nil) { + if !advance(status, oscStageOrder, v1alpha1.OSCConditionEndpointReady, endpointReady, endpointMsg, nil) { return r.finish(ctx, cluster, status, &state, nil) } @@ -175,7 +175,7 @@ func (r *ObjectStorageClusterReconciler) finish( if reconcileErr != nil { return ctrl.Result{}, reconcileErr } - if aggregateReady(status, v1alpha1.OSCConditionReady) { + if aggregateReady(status) { return ctrl.Result{}, nil } return ctrl.Result{RequeueAfter: r.Cfg.RequeueInterval}, nil diff --git a/images/controller/internal/controller/shared.go b/images/controller/internal/controller/shared.go index 430191f..8fa7312 100644 --- a/images/controller/internal/controller/shared.go +++ b/images/controller/internal/controller/shared.go @@ -44,6 +44,11 @@ const ( reasonWaitingForPrev = "WaitingForPrev" ) +// conditionReady is the aggregate readiness condition type. Both CRs use it +// (v1alpha1.OSCConditionReady and v1alpha1.OBConditionReady both equal "Ready"), +// so the shared FSM helpers gate it by this single invariant. +const conditionReady = "Ready" + // statusBuilder accumulates condition updates during a single reconcile and is // flushed onto the CR status at the end. It is intentionally CR-agnostic: both // reconcilers share it. @@ -72,14 +77,14 @@ func (s *statusBuilder) setCondition(condType string, condStatus metav1.Conditio // reports whether the FSM may proceed to the next stage. When the stage is not // done (error or in-progress), every downstream stage and the aggregate Ready // are gated as False. -func advance(s *statusBuilder, stageOrder []string, readyType, condType string, done bool, message string, err error) bool { +func advance(s *statusBuilder, stageOrder []string, condType string, done bool, message string, err error) bool { switch { case err != nil: s.setCondition(condType, metav1.ConditionFalse, reasonError, err.Error()) - gateAfter(s, stageOrder, readyType, condType) + gateAfter(s, stageOrder, condType) case !done: s.setCondition(condType, metav1.ConditionFalse, reasonInProgress, message) - gateAfter(s, stageOrder, readyType, condType) + gateAfter(s, stageOrder, condType) default: s.setCondition(condType, metav1.ConditionTrue, reasonReady, message) return true @@ -88,8 +93,8 @@ func advance(s *statusBuilder, stageOrder []string, readyType, condType string, } // gateAfter marks every stage strictly after afterStage, plus the aggregate -// readyType, as False/WaitingForPrev. -func gateAfter(s *statusBuilder, stageOrder []string, readyType, afterStage string) { +// Ready condition, as False/WaitingForPrev. +func gateAfter(s *statusBuilder, stageOrder []string, afterStage string) { startIdx := -1 for i, t := range stageOrder { if t == afterStage { @@ -103,7 +108,7 @@ func gateAfter(s *statusBuilder, stageOrder []string, readyType, afterStage stri fmt.Sprintf("waiting for %s", afterStage)) } } - s.setCondition(readyType, metav1.ConditionFalse, reasonWaitingForPrev, + s.setCondition(conditionReady, metav1.ConditionFalse, reasonWaitingForPrev, fmt.Sprintf("waiting for %s", afterStage)) } @@ -135,11 +140,11 @@ func derivePhase(conditions []metav1.Condition, stageOrder []string) string { return v1alpha1.PhaseReady } -// aggregateReady reports whether the builder's most recent write of readyType -// is True. -func aggregateReady(s *statusBuilder, readyType string) bool { +// aggregateReady reports whether the builder's most recent write of the +// aggregate Ready condition is True. +func aggregateReady(s *statusBuilder) bool { for i := len(s.conditions) - 1; i >= 0; i-- { - if s.conditions[i].Type == readyType { + if s.conditions[i].Type == conditionReady { return s.conditions[i].Status == metav1.ConditionTrue } } diff --git a/images/controller/internal/controller/shared_test.go b/images/controller/internal/controller/shared_test.go index 788472a..f7e4955 100644 --- a/images/controller/internal/controller/shared_test.go +++ b/images/controller/internal/controller/shared_test.go @@ -54,7 +54,7 @@ func TestDerivePhase(t *testing.T) { func TestAdvance(t *testing.T) { // Success advances and records True. sb := newStatusBuilder(1) - if !advance(sb, testStages, "Ready", "A", true, "done", nil) { + if !advance(sb, testStages, "A", true, "done", nil) { t.Fatalf("advance(done): want true") } if c := apimeta.FindStatusCondition(sb.conditions, "A"); c == nil || c.Status != metav1.ConditionTrue { @@ -63,7 +63,7 @@ func TestAdvance(t *testing.T) { // Error stops and gates the aggregate. sb = newStatusBuilder(1) - if advance(sb, testStages, "Ready", "A", false, "", errors.New("boom")) { + if advance(sb, testStages, "A", false, "", errors.New("boom")) { t.Fatalf("advance(err): want false") } if c := apimeta.FindStatusCondition(sb.conditions, "A"); c == nil || c.Status != metav1.ConditionFalse || c.Reason != reasonError { @@ -76,7 +76,7 @@ func TestAdvance(t *testing.T) { func TestGateAfter(t *testing.T) { sb := newStatusBuilder(1) - gateAfter(sb, []string{"A", "B", "C"}, "Ready", "A") + gateAfter(sb, []string{"A", "B", "C"}, "A") for _, downstream := range []string{"B", "C", "Ready"} { c := apimeta.FindStatusCondition(sb.conditions, downstream) @@ -92,11 +92,11 @@ func TestGateAfter(t *testing.T) { func TestAggregateReady(t *testing.T) { sb := newStatusBuilder(1) - if aggregateReady(sb, "Ready") { + if aggregateReady(sb) { t.Errorf("aggregateReady(empty)=true, want false") } sb.setCondition("Ready", metav1.ConditionTrue, reasonReady, "") - if !aggregateReady(sb, "Ready") { + if !aggregateReady(sb) { t.Errorf("aggregateReady(True)=false, want true") } } From fc964fc863b599ec67455028e58cff64c36e83df Mon Sep 17 00:00:00 2001 From: "v.oleynikov" Date: Sun, 28 Jun 2026 16:09:52 +0300 Subject: [PATCH 3/5] fix: clear remaining go_linter findings (unparam, gci) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two more findings surfaced once the controller package was clean (the go_linter action fails fast per module, so it only reports the next module after the previous one passes): - webhooks/handlers/validator_test.go: the obObj test helper's clusterRef param always received "c1" (unparam) — drop it and set it inside. - hooks/go/main.go: gci wanted the third-party and module-local imports in a single group (no blank-line split). Co-Authored-By: Claude Opus 4.8 (1M context) --- hooks/go/main.go | 1 - images/webhooks/handlers/validator_test.go | 14 +++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/hooks/go/main.go b/hooks/go/main.go index e478189..3c2c578 100644 --- a/hooks/go/main.go +++ b/hooks/go/main.go @@ -18,7 +18,6 @@ package main import ( "github.com/deckhouse/module-sdk/pkg/app" - _ "github.com/deckhouse/sds-object/hooks/go/020-webhook-certs" _ "github.com/deckhouse/sds-object/hooks/go/030-remove-finalizers-on-module-delete" ) diff --git a/images/webhooks/handlers/validator_test.go b/images/webhooks/handlers/validator_test.go index 9a531af..466f579 100644 --- a/images/webhooks/handlers/validator_test.go +++ b/images/webhooks/handlers/validator_test.go @@ -34,8 +34,8 @@ func listKinds() map[schema.GroupVersionResource]string { } } -func obObj(ns, name, clusterRef, bucketName string) *unstructured.Unstructured { - spec := map[string]interface{}{"clusterRef": clusterRef} +func obObj(ns, name, bucketName string) *unstructured.Unstructured { + spec := map[string]interface{}{"clusterRef": "c1"} if bucketName != "" { spec["bucketName"] = bucketName } @@ -62,20 +62,20 @@ func newFakeValidator(objs ...runtime.Object) *Validator { } func TestEffectiveBucketName(t *testing.T) { - if got := effectiveBucketName(obObj("a", "data", "c1", "")); got != "data" { + if got := effectiveBucketName(obObj("a", "data", "")); got != "data" { t.Errorf("effectiveBucketName(default)=%q, want data", got) } - if got := effectiveBucketName(obObj("a", "data", "c1", "custom")); got != "custom" { + if got := effectiveBucketName(obObj("a", "data", "custom")); got != "custom" { t.Errorf("effectiveBucketName(explicit)=%q, want custom", got) } } func TestObjectBucketValidate(t *testing.T) { // Existing bucket "x" on cluster c1. - v := newFakeValidator(obObj("a", "x", "c1", "")) + v := newFakeValidator(obObj("a", "x", "")) // Duplicate effective name on the same cluster -> deny. - dup := obObj("b", "y", "c1", "x") + dup := obObj("b", "y", "x") res, err := v.ObjectBucketValidate(context.Background(), nil, dup) if err != nil { t.Fatalf("ObjectBucketValidate(dup): %v", err) @@ -85,7 +85,7 @@ func TestObjectBucketValidate(t *testing.T) { } // Unique name -> allow (clusterRef missing only yields a warning). - uniq := obObj("b", "y", "c1", "") + uniq := obObj("b", "y", "") res, err = v.ObjectBucketValidate(context.Background(), nil, uniq) if err != nil { t.Fatalf("ObjectBucketValidate(uniq): %v", err) From d55aadb74504c2c250fdcbae9d8a7fbec17208f9 Mon Sep 17 00:00:00 2001 From: "v.oleynikov" Date: Sun, 28 Jun 2026 16:19:31 +0300 Subject: [PATCH 4/5] chore(werf): migrate build to container-base v1.1.8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Align the sds-object build with the other storage modules (e.g. sds-node-configurator, csi-ceph): consume base images through the `Images` map (`from: {{ index $.Images "…" }}` instead of `fromImage:`) and bump base-images to v1.1.8 from the container-base catalog. - Workflows: BASE_IMAGES_VERSION v0.5.79 -> v1.1.8 and switch the base_images.yml fetch URL to deckhouse/container-base/base-images. - .werf/base-images.yaml: drop the per-base-image artifact range loop (only the Images map is needed now). - .werf/images.yaml: expose the Images map to each per-image build context. - Builder renames: builder/alt -> builder/golang-alt, builder/golang-alpine -> builder/golang, builder/golang-alt-svace -> builder/alpine-svace, base/distroless -> builder/distroless, tools/jq -> jq, tools/yq -> yq. - images-digests: import jq from the catalog instead of `apk add jq`. The Go images build CGO-free (CGO_ENABLED=0), so the svace path uses the musl builder/alpine-svace and the default path uses builder/golang. The garage and seaweedfs images still vendor their upstream binaries into builder/distroless. `werf config render` resolves every `from:` to the v1.1.8 container-factory digests with no errors. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/build_dev.yml | 4 ++-- .github/workflows/build_prod.yml | 12 ++++++------ .werf/base-images.yaml | 9 +-------- .werf/bundle.yaml | 4 ++-- .werf/choose-edition.yaml | 2 +- .werf/images-digests.yaml | 9 ++++++--- .werf/images.yaml | 1 + .werf/release.yaml | 6 +++--- images/controller/werf.inc.yaml | 6 +++--- images/garage/werf.inc.yaml | 2 +- images/go-hooks/werf.inc.yaml | 4 ++-- images/seaweedfs/werf.inc.yaml | 2 +- images/webhooks/werf.inc.yaml | 6 +++--- 13 files changed, 32 insertions(+), 35 deletions(-) diff --git a/.github/workflows/build_dev.yml b/.github/workflows/build_dev.yml index d833f7e..6e88c9e 100644 --- a/.github/workflows/build_dev.yml +++ b/.github/workflows/build_dev.yml @@ -10,7 +10,7 @@ env: GOPROXY: ${{ secrets.GOPROXY }} SOURCE_REPO: ${{ secrets.SOURCE_REPO }} SOURCE_REPO_SSH_KEY: ${{ secrets.SOURCE_REPO_SSH_KEY }} - BASE_IMAGES_VERSION: "v0.5.79" + BASE_IMAGES_VERSION: "v1.1.8" on: #pull_request: # call from trivy_image_check.yaml, which in turn call from pull_request @@ -122,7 +122,7 @@ jobs: - name: Download base images and auth prepare run: | - wget https://fox.flant.com/api/v4/projects/deckhouse%2Fbase-images/packages/generic/base_images/$BASE_IMAGES_VERSION/base_images.yml -O base_images.yml + wget https://fox.flant.com/api/v4/projects/deckhouse%2Fcontainer-base%2Fbase-images/packages/generic/base_images/$BASE_IMAGES_VERSION/base_images.yml -O base_images.yml cat base_images.yml - uses: deckhouse/modules-actions/setup@v4 diff --git a/.github/workflows/build_prod.yml b/.github/workflows/build_prod.yml index c34c075..1c6ccbe 100644 --- a/.github/workflows/build_prod.yml +++ b/.github/workflows/build_prod.yml @@ -11,7 +11,7 @@ env: GOPROXY: ${{ secrets.GOPROXY }} SOURCE_REPO: ${{ secrets.SOURCE_REPO }} SOURCE_REPO_SSH_KEY: ${{ secrets.SOURCE_REPO_SSH_KEY }} - BASE_IMAGES_VERSION: "v0.5.79" + BASE_IMAGES_VERSION: "v1.1.8" on: push: tags: @@ -39,7 +39,7 @@ jobs: - name: Download base images and auth prepare run: | - wget https://fox.flant.com/api/v4/projects/deckhouse%2Fbase-images/packages/generic/base_images/$BASE_IMAGES_VERSION/base_images.yml -O base_images.yml + wget https://fox.flant.com/api/v4/projects/deckhouse%2Fcontainer-base%2Fbase-images/packages/generic/base_images/$BASE_IMAGES_VERSION/base_images.yml -O base_images.yml cat base_images.yml - uses: deckhouse/modules-actions/setup@v4 @@ -82,7 +82,7 @@ jobs: - name: Download base images run: | - wget https://fox.flant.com/api/v4/projects/deckhouse%2Fbase-images/packages/generic/base_images/$BASE_IMAGES_VERSION/base_images.yml -O base_images.yml + wget https://fox.flant.com/api/v4/projects/deckhouse%2Fcontainer-base%2Fbase-images/packages/generic/base_images/$BASE_IMAGES_VERSION/base_images.yml -O base_images.yml cat base_images.yml - uses: deckhouse/modules-actions/setup@v4 @@ -125,7 +125,7 @@ jobs: - name: Download base images run: | - wget https://fox.flant.com/api/v4/projects/deckhouse%2Fbase-images/packages/generic/base_images/$BASE_IMAGES_VERSION/base_images.yml -O base_images.yml + wget https://fox.flant.com/api/v4/projects/deckhouse%2Fcontainer-base%2Fbase-images/packages/generic/base_images/$BASE_IMAGES_VERSION/base_images.yml -O base_images.yml cat base_images.yml - uses: deckhouse/modules-actions/setup@v4 @@ -168,7 +168,7 @@ jobs: - name: Download base images run: | - wget https://fox.flant.com/api/v4/projects/deckhouse%2Fbase-images/packages/generic/base_images/$BASE_IMAGES_VERSION/base_images.yml -O base_images.yml + wget https://fox.flant.com/api/v4/projects/deckhouse%2Fcontainer-base%2Fbase-images/packages/generic/base_images/$BASE_IMAGES_VERSION/base_images.yml -O base_images.yml cat base_images.yml - uses: deckhouse/modules-actions/setup@v4 @@ -211,7 +211,7 @@ jobs: - name: Download base images run: | - wget https://fox.flant.com/api/v4/projects/deckhouse%2Fbase-images/packages/generic/base_images/$BASE_IMAGES_VERSION/base_images.yml -O base_images.yml + wget https://fox.flant.com/api/v4/projects/deckhouse%2Fcontainer-base%2Fbase-images/packages/generic/base_images/$BASE_IMAGES_VERSION/base_images.yml -O base_images.yml cat base_images.yml - uses: deckhouse/modules-actions/setup@v4 diff --git a/.werf/base-images.yaml b/.werf/base-images.yaml index 694fae2..68a575b 100644 --- a/.werf/base-images.yaml +++ b/.werf/base-images.yaml @@ -1,7 +1,7 @@ # Base Images {{- $baseImages := .Files.Get "base_images.yml" | fromYaml }} {{- range $k, $v := $baseImages }} - {{ $baseImagePath := (printf "%s@%s" $baseImages.REGISTRY_PATH (trimSuffix "/" $v)) }} + {{- $baseImagePath := (printf "%s@%s" $baseImages.REGISTRY_PATH (trimSuffix "/" $v)) }} {{- if ne $k "REGISTRY_PATH" }} {{- $_ := set $baseImages $k $baseImagePath }} {{- end }} @@ -9,11 +9,4 @@ {{- $_ := unset $baseImages "REGISTRY_PATH" }} {{- $_ := set . "Images" $baseImages }} -# base images artifacts -{{- range $k, $v := .Images }} ---- -image: {{ $k }} -from: {{ $v }} -final: false -{{- end }} diff --git a/.werf/bundle.yaml b/.werf/bundle.yaml index 3cd40a0..35c4f4f 100644 --- a/.werf/bundle.yaml +++ b/.werf/bundle.yaml @@ -1,6 +1,6 @@ --- image: docs-generator -fromImage: builder/alt +from: {{ index $.Images "builder/golang-alt" }} final: false git: @@ -25,7 +25,7 @@ shell: # Bundle image, stored in your.registry.io/modules/: --- image: bundle -fromImage: builder/scratch +from: {{ index $.Images "builder/scratch" }} import: # Rendering .werf/images-digests.yaml is required! diff --git a/.werf/choose-edition.yaml b/.werf/choose-edition.yaml index 590efe1..b31935d 100644 --- a/.werf/choose-edition.yaml +++ b/.werf/choose-edition.yaml @@ -1,6 +1,6 @@ --- image: choose-edition -fromImage: builder/alt +from: {{ index $.Images "builder/golang-alt" }} fromCacheVersion: {{ div .Commit.Date.Unix (mul 60 60 24 30) }} git: diff --git a/.werf/images-digests.yaml b/.werf/images-digests.yaml index 69790ce..274075c 100644 --- a/.werf/images-digests.yaml +++ b/.werf/images-digests.yaml @@ -13,7 +13,12 @@ # Images Digest: a files with all image digests to be able to use them in helm templates of a module --- image: images-digests -fromImage: builder/alpine +from: {{ index $.Images "builder/alpine" }} +import: + - from: {{ index $.Images "jq" }} + add: /usr/bin/jq + to: /usr/bin/jq + before: setup dependencies: {{- range $ImageID := $ImagesIDList }} {{- $ImageNameCamel := $ImageID | splitList "/" | last | camelcase | untitle }} @@ -24,8 +29,6 @@ dependencies: targetEnv: MODULE_IMAGE_DIGEST_{{ $ImageNameCamel }} {{- end }} shell: - beforeInstall: - - apk add --no-cache jq setup: - | env | grep MODULE_IMAGE_DIGEST | jq -Rn ' diff --git a/.werf/images.yaml b/.werf/images.yaml index 6c4822e..4d3aea3 100644 --- a/.werf/images.yaml +++ b/.werf/images.yaml @@ -10,6 +10,7 @@ {{- range $path, $content := $ImagesBuildFiles }} {{- $ctx := dict }} {{- $_ := set $ctx "ImageName" ($path | split "/")._1 }} + {{- $_ := set $ctx "Images" $.Images }} {{- $_ := set $ctx "SOURCE_REPO" $Root.SOURCE_REPO }} {{- $_ := set $ctx "MODULE_EDITION" $.MODULE_EDITION }} {{- $_ := set $ctx "SVACE_ENABLED" (env "SVACE_ENABLED" "false") }} diff --git a/.werf/release.yaml b/.werf/release.yaml index 04cace6..2f08958 100644 --- a/.werf/release.yaml +++ b/.werf/release.yaml @@ -1,7 +1,7 @@ # Release image, stored in your.registry.io/modules//release: --- image: release-channel-version-artifact -fromImage: builder/alpine +from: {{ index $.Images "builder/alpine" }} final: false git: - add: / @@ -13,7 +13,7 @@ git: setup: - '**/*' import: - - image: tools/yq + - from: {{ index $.Images "yq" }} add: /usr/bin/yq to: /usr/bin/yq before: install @@ -24,7 +24,7 @@ shell: - cp -f CHANGELOG/{{ env "MODULES_MODULE_TAG" "local" }}.yml /changelog.yaml || touch /changelog.yaml --- image: release-channel-version -fromImage: builder/scratch +from: {{ index $.Images "builder/scratch" }} import: - image: release-channel-version-artifact add: / diff --git a/images/controller/werf.inc.yaml b/images/controller/werf.inc.yaml index fd33992..79f0340 100644 --- a/images/controller/werf.inc.yaml +++ b/images/controller/werf.inc.yaml @@ -1,6 +1,6 @@ --- image: {{ .ModuleNamePrefix }}{{ .ImageName }}-src-artifact -fromImage: builder/src +from: {{ index $.Images "builder/src" }} final: false git: @@ -21,7 +21,7 @@ shell: --- image: {{ .ModuleNamePrefix }}{{ .ImageName }}-golang-artifact -fromImage: {{ eq .SVACE_ENABLED "false" | ternary "builder/golang-alpine" "builder/golang-alt-svace" }} +from: {{ index $.Images (eq .SVACE_ENABLED "false" | ternary "builder/golang" "builder/alpine-svace") }} final: false import: @@ -48,7 +48,7 @@ shell: --- image: {{ .ModuleNamePrefix }}{{ .ImageName }} -fromImage: base/distroless +from: {{ index $.Images "builder/distroless" }} import: - image: {{ .ModuleNamePrefix }}{{ .ImageName }}-golang-artifact diff --git a/images/garage/werf.inc.yaml b/images/garage/werf.inc.yaml index d2f5139..c9c6586 100644 --- a/images/garage/werf.inc.yaml +++ b/images/garage/werf.inc.yaml @@ -17,7 +17,7 @@ final: false --- image: {{ .ModuleNamePrefix }}{{ .ImageName }} -fromImage: base/distroless +from: {{ index $.Images "builder/distroless" }} import: - image: {{ .ModuleNamePrefix }}{{ .ImageName }}-artifact diff --git a/images/go-hooks/werf.inc.yaml b/images/go-hooks/werf.inc.yaml index 88fcf54..fab0014 100644 --- a/images/go-hooks/werf.inc.yaml +++ b/images/go-hooks/werf.inc.yaml @@ -1,6 +1,6 @@ --- image: {{ .ModuleNamePrefix }}{{ .ImageName }}-src-artifact -fromImage: builder/src +from: {{ index $.Images "builder/src" }} final: false git: - add: {{ .ModuleDir }}/hooks/go @@ -17,7 +17,7 @@ shell: --- image: {{ .ModuleNamePrefix }}{{ .ImageName }}-artifact -fromImage: {{ eq .SVACE_ENABLED "false" | ternary "builder/golang-alpine" "builder/golang-alt-svace" }} +from: {{ index $.Images (eq .SVACE_ENABLED "false" | ternary "builder/golang" "builder/alpine-svace") }} final: false import: diff --git a/images/seaweedfs/werf.inc.yaml b/images/seaweedfs/werf.inc.yaml index a1a6740..5a94565 100644 --- a/images/seaweedfs/werf.inc.yaml +++ b/images/seaweedfs/werf.inc.yaml @@ -16,7 +16,7 @@ final: false --- image: {{ .ModuleNamePrefix }}{{ .ImageName }} -fromImage: base/distroless +from: {{ index $.Images "builder/distroless" }} import: - image: {{ .ModuleNamePrefix }}{{ .ImageName }}-artifact diff --git a/images/webhooks/werf.inc.yaml b/images/webhooks/werf.inc.yaml index f492109..8e4a935 100644 --- a/images/webhooks/werf.inc.yaml +++ b/images/webhooks/werf.inc.yaml @@ -1,6 +1,6 @@ --- image: {{ .ModuleNamePrefix }}{{ .ImageName }}-src-artifact -fromImage: builder/src +from: {{ index $.Images "builder/src" }} final: false git: @@ -20,7 +20,7 @@ shell: --- image: {{ .ModuleNamePrefix }}{{ .ImageName }}-golang-artifact -fromImage: {{ eq .SVACE_ENABLED "false" | ternary "builder/golang-alpine" "builder/golang-alt-svace" }} +from: {{ index $.Images (eq .SVACE_ENABLED "false" | ternary "builder/golang" "builder/alpine-svace") }} final: false import: @@ -47,7 +47,7 @@ shell: --- image: {{ .ModuleNamePrefix }}{{ .ImageName }} -fromImage: base/distroless +from: {{ index $.Images "builder/distroless" }} git: {{- include "image mount points" . }} From 17b9259cbb09997be9b22ad6ea4630b279cd5f5d Mon Sep 17 00:00:00 2001 From: "v.oleynikov" Date: Sun, 28 Jun 2026 16:30:53 +0300 Subject: [PATCH 5/5] chore(werf): add image mount points to garage and seaweedfs images The controller and webhooks images already declare a mount-points.yaml and include the "image mount points" template in their final stage; the garage and seaweedfs images did not. Every final image in the sibling storage modules (e.g. csi-nfs, including vendored-binary images) wires this mechanism, so add it here for consistency. Both declare an empty dirs list (their data paths are provided by Kubernetes volume mounts at runtime), matching the controller image. Co-Authored-By: Claude Opus 4.8 (1M context) --- images/garage/mount-points.yaml | 1 + images/garage/werf.inc.yaml | 2 ++ images/seaweedfs/mount-points.yaml | 1 + images/seaweedfs/werf.inc.yaml | 2 ++ 4 files changed, 6 insertions(+) create mode 100644 images/garage/mount-points.yaml create mode 100644 images/seaweedfs/mount-points.yaml diff --git a/images/garage/mount-points.yaml b/images/garage/mount-points.yaml new file mode 100644 index 0000000..eefff43 --- /dev/null +++ b/images/garage/mount-points.yaml @@ -0,0 +1 @@ +dirs: [] diff --git a/images/garage/werf.inc.yaml b/images/garage/werf.inc.yaml index c9c6586..b3a9dec 100644 --- a/images/garage/werf.inc.yaml +++ b/images/garage/werf.inc.yaml @@ -24,6 +24,8 @@ import: add: /garage to: /garage before: setup +git: +{{- include "image mount points" . }} imageSpec: config: diff --git a/images/seaweedfs/mount-points.yaml b/images/seaweedfs/mount-points.yaml new file mode 100644 index 0000000..eefff43 --- /dev/null +++ b/images/seaweedfs/mount-points.yaml @@ -0,0 +1 @@ +dirs: [] diff --git a/images/seaweedfs/werf.inc.yaml b/images/seaweedfs/werf.inc.yaml index 5a94565..f093b82 100644 --- a/images/seaweedfs/werf.inc.yaml +++ b/images/seaweedfs/werf.inc.yaml @@ -23,6 +23,8 @@ import: add: /usr/bin/weed to: /weed before: setup +git: +{{- include "image mount points" . }} imageSpec: config: