diff --git a/go.mod b/go.mod index b191f9dd..da33c207 100644 --- a/go.mod +++ b/go.mod @@ -27,7 +27,7 @@ require ( github.com/pkg/errors v0.9.1 github.com/stretchr/testify v1.11.1 github.com/tidwall/gjson v1.19.0 - github.com/werf/nelm v1.27.2 + github.com/werf/nelm v1.28.0 google.golang.org/protobuf v1.36.11 gopkg.in/yaml.v3 v3.0.1 helm.sh/helm/v3 v3.19.5 diff --git a/go.sum b/go.sum index 2c4f5efc..e0ccdc29 100644 --- a/go.sum +++ b/go.sum @@ -548,8 +548,8 @@ github.com/werf/lockgate v0.1.1 h1:S400JFYjtWfE4i4LY9FA8zx0fMdfui9DPrBiTciCrx4= github.com/werf/lockgate v0.1.1/go.mod h1:0yIFSLq9ausy6ejNxF5uUBf/Ib6daMAfXuCaTMZJzIE= github.com/werf/logboek v0.6.1 h1:oEe6FkmlKg0z0n80oZjLplj6sXcBeLleCkjfOOZEL2g= github.com/werf/logboek v0.6.1/go.mod h1:Gez5J4bxekyr6MxTmIJyId1F61rpO+0/V4vjCIEIZmk= -github.com/werf/nelm v1.27.2 h1:I75+k8zzEWYMU6yZClyzjQeJkDuIMrkOeTXix0vUcUg= -github.com/werf/nelm v1.27.2/go.mod h1:D3uU5e1dSBc0l0oo/iB6SjM2sLaXICqRDSWXAYF+vpk= +github.com/werf/nelm v1.28.0 h1:pJcf2M+7grLS2CxIubu0JciFjAt+Lz7tLY3YmYBjZ6U= +github.com/werf/nelm v1.28.0/go.mod h1:D3uU5e1dSBc0l0oo/iB6SjM2sLaXICqRDSWXAYF+vpk= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= diff --git a/pkg/helm/nelm/nelm.go b/pkg/helm/nelm/nelm.go index e60c0fad..bbec9925 100644 --- a/pkg/helm/nelm/nelm.go +++ b/pkg/helm/nelm/nelm.go @@ -633,6 +633,14 @@ func (c *NelmClient) Render(releaseName, modulePath string, valuesPaths, setValu var result strings.Builder for _, resource := range chartRenderResult.Resources { + // Keep only regular release resources to match helm3 Render output. + // Hooks and standalone CRDs may legitimately be absent from the + // cluster, so they must not reach the release checksum and the + // absent-resources monitor. + if resource.StoreAs != common.StoreAsRegular { + continue + } + b, err := yaml.Marshal(resource.Unstruct) if err != nil { return "", fmt.Errorf("marshal resource: %w", err) diff --git a/pkg/helm/nelm/nelm_test.go b/pkg/helm/nelm/nelm_test.go index 8b1f2ad5..a149a9cd 100644 --- a/pkg/helm/nelm/nelm_test.go +++ b/pkg/helm/nelm/nelm_test.go @@ -4,11 +4,16 @@ import ( "bytes" "context" "encoding/json" + "strings" "testing" "github.com/deckhouse/deckhouse/pkg/log" "github.com/stretchr/testify/assert" + "github.com/werf/nelm/pkg/action" + "github.com/werf/nelm/pkg/common" nelmLog "github.com/werf/nelm/pkg/log" + "github.com/werf/nelm/pkg/resource/spec" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "github.com/flant/addon-operator/pkg" ) @@ -44,3 +49,62 @@ func Test_NelmLogger_ModuleFromContext(t *testing.T) { _, hasModule := neutral[pkg.LogKeyModule] assert.False(t, hasModule, "module must be absent when context has no module") } + +func Test_NelmClient_Render_KeepsOnlyRegularResources(t *testing.T) { + cl := NewNelmClient(&CommonOptions{}, log.NewNop().Named("nelm"), nil) + cl.actions = &fakeNelmActions{ + chartRenderResult: &action.ChartRenderResultV2{ + Resources: []*spec.ResourceSpec{ + renderedResource("apps/v1", "Deployment", "regular-deployment", common.StoreAsRegular), + renderedResource("batch/v1", "Job", "pre-delete-hook", common.StoreAsHook), + renderedResource("apps/v1", "Deployment", "another-regular-deployment", common.StoreAsRegular), + renderedResource("apiextensions.k8s.io/v1", "CustomResourceDefinition", "standalone-crd", common.StoreAsNone), + }, + }, + } + + rendered, err := cl.Render("test-release", "/some/chart", nil, nil, nil, "test-ns", false) + assert.NoError(t, err) + + assert.Contains(t, rendered, "regular-deployment") + assert.Contains(t, rendered, "another-regular-deployment") + assert.NotContains(t, rendered, "pre-delete-hook", "helm hooks must not be rendered") + assert.NotContains(t, rendered, "standalone-crd", "standalone CRDs must not be rendered") + assert.Equal(t, 1, strings.Count(rendered, "---"), "two regular resources must be joined by a single separator") +} + +func renderedResource(apiVersion, kind, name string, storeAs common.StoreAs) *spec.ResourceSpec { + return &spec.ResourceSpec{ + Unstruct: &unstructured.Unstructured{Object: map[string]any{ + "apiVersion": apiVersion, + "kind": kind, + "metadata": map[string]any{"name": name}, + }}, + StoreAs: storeAs, + } +} + +// fakeNelmActions stubs nelm calls in tests; only ChartRender returns data. +type fakeNelmActions struct { + chartRenderResult *action.ChartRenderResultV2 +} + +func (f *fakeNelmActions) ReleaseGet(_ context.Context, _, _ string, _ action.ReleaseGetOptions) (*action.ReleaseGetResultV1, error) { + return nil, nil +} + +func (f *fakeNelmActions) ReleaseInstall(_ context.Context, _, _ string, _ action.ReleaseInstallOptions) error { + return nil +} + +func (f *fakeNelmActions) ReleaseUninstall(_ context.Context, _, _ string, _ action.ReleaseUninstallOptions) error { + return nil +} + +func (f *fakeNelmActions) ReleaseList(_ context.Context, _ action.ReleaseListOptions) (*action.ReleaseListResultV1, error) { + return nil, nil +} + +func (f *fakeNelmActions) ChartRender(_ context.Context, _ action.ChartRenderOptions) (*action.ChartRenderResultV2, error) { + return f.chartRenderResult, nil +}