From 1277d6639b41e899117b59b3b904669d2b8dfc62 Mon Sep 17 00:00:00 2001 From: Dmitry Lopatin Date: Mon, 20 Apr 2026 15:17:26 +0300 Subject: [PATCH 1/7] fix(module): avoid queue blocking on invalid module config Signed-off-by: Dmitry Lopatin --- .../hook.go | 4 + .../hook_test.go | 1 + .../hooks/discovery-workload-nodes/hook.go | 4 + .../discovery-workload-nodes/hook_test.go | 84 +++++++++++++++ .../hooks/generate-secret-for-dvcr/hook.go | 4 + .../generate-secret-for-dvcr/hook_test.go | 1 + .../hooks/tls-certificates-api-proxy/main.go | 18 +++- .../tls-certificates-api-proxy/main_test.go | 37 +++++++ .../pkg/hooks/tls-certificates-api/main.go | 19 +++- .../hooks/tls-certificates-api/main_test.go | 37 +++++++ .../pkg/hooks/tls-certificates-audit/hook.go | 4 + .../hooks/tls-certificates-controller/hook.go | 19 +++- .../tls-certificates-controller/hook_test.go | 37 +++++++ .../pkg/hooks/tls-certificates-dvcr/hook.go | 4 + .../hooks/tls-certificates-dvcr/hook_test.go | 37 +++++++ .../pkg/hooks/validate-module-config/hook.go | 35 +++++- .../hooks/validate-module-config/hook_test.go | 102 +++++++++++++----- images/hooks/pkg/settings/module_config.go | 32 ++++++ .../hooks/pkg/settings/module_config_test.go | 68 ++++++++++++ templates/_helpers.tpl | 2 +- 20 files changed, 513 insertions(+), 36 deletions(-) create mode 100644 images/hooks/pkg/hooks/discovery-workload-nodes/hook_test.go create mode 100644 images/hooks/pkg/hooks/tls-certificates-api-proxy/main_test.go create mode 100644 images/hooks/pkg/hooks/tls-certificates-api/main_test.go create mode 100644 images/hooks/pkg/hooks/tls-certificates-controller/hook_test.go create mode 100644 images/hooks/pkg/hooks/tls-certificates-dvcr/hook_test.go create mode 100644 images/hooks/pkg/settings/module_config.go create mode 100644 images/hooks/pkg/settings/module_config_test.go diff --git a/images/hooks/pkg/hooks/discovery-clusterip-service-for-dvcr/hook.go b/images/hooks/pkg/hooks/discovery-clusterip-service-for-dvcr/hook.go index 6d147de18d..411e602cd3 100644 --- a/images/hooks/pkg/hooks/discovery-clusterip-service-for-dvcr/hook.go +++ b/images/hooks/pkg/hooks/discovery-clusterip-service-for-dvcr/hook.go @@ -65,6 +65,10 @@ var configDiscoveryService = &pkg.HookConfig{ } func handleDiscoveryService(_ context.Context, input *pkg.HookInput) error { + if !settings.HasModuleConfig(input) { + return nil + } + clusterIP := getClusterIP(input) if clusterIP == "" { diff --git a/images/hooks/pkg/hooks/discovery-clusterip-service-for-dvcr/hook_test.go b/images/hooks/pkg/hooks/discovery-clusterip-service-for-dvcr/hook_test.go index 35681c1404..4d289aeffc 100644 --- a/images/hooks/pkg/hooks/discovery-clusterip-service-for-dvcr/hook_test.go +++ b/images/hooks/pkg/hooks/discovery-clusterip-service-for-dvcr/hook_test.go @@ -64,6 +64,7 @@ var _ = Describe("DiscoveryClusterIPServiceForDVCR", func() { } newInput := func() *pkg.HookInput { + values.GetMock.When("virtualization.internal.moduleConfig").Then(gjson.Parse(`{"dvcr":{},"virtualMachineCIDRs":["10.0.0.0/24"]}`)) return &pkg.HookInput{ Snapshots: snapshots, Values: values, diff --git a/images/hooks/pkg/hooks/discovery-workload-nodes/hook.go b/images/hooks/pkg/hooks/discovery-workload-nodes/hook.go index cd0d710dbf..ec35fbcee7 100644 --- a/images/hooks/pkg/hooks/discovery-workload-nodes/hook.go +++ b/images/hooks/pkg/hooks/discovery-workload-nodes/hook.go @@ -79,6 +79,10 @@ var configDiscoveryService = &pkg.HookConfig{ } func handleDiscoveryNodes(_ context.Context, input *pkg.HookInput) error { + if !settings.HasModuleConfig(input) { + return nil + } + nodeCount := len(input.Snapshots.Get(discoveryNodesSnapshot)) input.Values.Set(virtHandlerNodeCountPath, nodeCount) diff --git a/images/hooks/pkg/hooks/discovery-workload-nodes/hook_test.go b/images/hooks/pkg/hooks/discovery-workload-nodes/hook_test.go new file mode 100644 index 0000000000..de0cf28ce5 --- /dev/null +++ b/images/hooks/pkg/hooks/discovery-workload-nodes/hook_test.go @@ -0,0 +1,84 @@ +/* +Copyright 2026 Flant JSC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package discovery_workload_nodes + +import ( + "context" + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/tidwall/gjson" + + "github.com/deckhouse/deckhouse/pkg/log" + "github.com/deckhouse/module-sdk/pkg" + "github.com/deckhouse/module-sdk/testing/mock" +) + +func TestDiscoveryWorkloadNodes(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "DiscoveryWorkloadNodes Suite") +} + +var _ = Describe("DiscoveryWorkloadNodes", func() { + var ( + snapshots *mock.SnapshotsMock + values *mock.OutputPatchableValuesCollectorMock + ) + + newInput := func() *pkg.HookInput { + return &pkg.HookInput{ + Snapshots: snapshots, + Values: values, + Logger: log.NewNop(), + } + } + + BeforeEach(func() { + snapshots = mock.NewSnapshotsMock(GinkgoT()) + values = mock.NewPatchableValuesCollectorMock(GinkgoT()) + }) + + AfterEach(func() { + snapshots = nil + values = nil + }) + + It("should do nothing when copied module config is absent", func() { + values.GetMock.When("virtualization.internal.moduleConfig").Then(gjson.Result{}) + Expect(handleDiscoveryNodes(context.Background(), newInput())).To(Succeed()) + }) + + It("should set node count when copied module config exists", func() { + values.GetMock.When("virtualization.internal.moduleConfig").Then(gjson.Parse(`{"dvcr":{},"virtualMachineCIDRs":["10.0.0.0/24"]}`)) + snapshots.GetMock.When(discoveryNodesSnapshot).Then([]pkg.Snapshot{ + mock.NewSnapshotMock(GinkgoT()), + mock.NewSnapshotMock(GinkgoT()), + }) + snapshots.GetMock.When(kubevirtConfigSnapshot).Then([]pkg.Snapshot{}) + + setCalls := 0 + values.SetMock.Set(func(path string, v any) { + setCalls++ + Expect(path).To(Equal(virtHandlerNodeCountPath)) + Expect(v).To(Equal(2)) + }) + + Expect(handleDiscoveryNodes(context.Background(), newInput())).To(Succeed()) + Expect(setCalls).To(Equal(1)) + }) +}) diff --git a/images/hooks/pkg/hooks/generate-secret-for-dvcr/hook.go b/images/hooks/pkg/hooks/generate-secret-for-dvcr/hook.go index 2d8c30ff42..1fb2ce9521 100644 --- a/images/hooks/pkg/hooks/generate-secret-for-dvcr/hook.go +++ b/images/hooks/pkg/hooks/generate-secret-for-dvcr/hook.go @@ -74,6 +74,10 @@ var configDVCRSecrets = &pkg.HookConfig{ } func handlerDVCRSecrets(_ context.Context, input *pkg.HookInput) error { + if !settings.HasModuleConfig(input) { + return nil + } + dataFromSecret, err := getDVCRSecretsFromSecrets(input) if err != nil { return err diff --git a/images/hooks/pkg/hooks/generate-secret-for-dvcr/hook_test.go b/images/hooks/pkg/hooks/generate-secret-for-dvcr/hook_test.go index 11cc500d15..b08180e2dd 100644 --- a/images/hooks/pkg/hooks/generate-secret-for-dvcr/hook_test.go +++ b/images/hooks/pkg/hooks/generate-secret-for-dvcr/hook_test.go @@ -70,6 +70,7 @@ var _ = Describe("DVCR Secrets", func() { } newInput := func() *pkg.HookInput { + values.GetMock.When("virtualization.internal.moduleConfig").Then(gjson.Parse(`{"dvcr":{},"virtualMachineCIDRs":["10.0.0.0/24"]}`)) return &pkg.HookInput{ Snapshots: snapshots, Values: values, diff --git a/images/hooks/pkg/hooks/tls-certificates-api-proxy/main.go b/images/hooks/pkg/hooks/tls-certificates-api-proxy/main.go index 5834bf6584..0145edcea2 100644 --- a/images/hooks/pkg/hooks/tls-certificates-api-proxy/main.go +++ b/images/hooks/pkg/hooks/tls-certificates-api-proxy/main.go @@ -17,16 +17,18 @@ limitations under the License. package tls_certificates_api_proxy import ( + "context" "fmt" v1 "k8s.io/api/certificates/v1" tlscertificate "github.com/deckhouse/module-sdk/common-hooks/tls-certificate" "github.com/deckhouse/module-sdk/pkg" + "github.com/deckhouse/module-sdk/pkg/registry" "github.com/deckhouse/virtualization/hooks/pkg/settings" ) -var _ = tlscertificate.RegisterInternalTLSHookEM(tlscertificate.GenSelfSignedTLSHookConf{ +var conf = tlscertificate.GenSelfSignedTLSHookConf{ CN: settings.APIProxyCertCN, TLSSecretName: "virtualization-api-proxy-tls", Namespace: settings.ModuleNamespace, @@ -34,4 +36,16 @@ var _ = tlscertificate.RegisterInternalTLSHookEM(tlscertificate.GenSelfSignedTLS FullValuesPathPrefix: fmt.Sprintf("%s.internal.apiserver.proxyCert", settings.ModuleName), CommonCAValuesPath: fmt.Sprintf("%s.internal.rootCA", settings.ModuleName), Usages: []v1.KeyUsage{v1.UsageClientAuth}, -}) +} + +var reconcile = func(conf tlscertificate.GenSelfSignedTLSHookConf) pkg.ReconcileFunc { + return func(ctx context.Context, input *pkg.HookInput) error { + if !settings.HasModuleConfig(input) { + return nil + } + + return tlscertificate.GenSelfSignedTLS(conf)(ctx, input) + } +} + +var _ = registry.RegisterFunc(tlscertificate.GenSelfSignedTLSConfig(conf), reconcile(conf)) diff --git a/images/hooks/pkg/hooks/tls-certificates-api-proxy/main_test.go b/images/hooks/pkg/hooks/tls-certificates-api-proxy/main_test.go new file mode 100644 index 0000000000..5f0d4955f6 --- /dev/null +++ b/images/hooks/pkg/hooks/tls-certificates-api-proxy/main_test.go @@ -0,0 +1,37 @@ +/* +Copyright 2026 Flant JSC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package tls_certificates_api_proxy + +import ( + "context" + "testing" + + "github.com/tidwall/gjson" + + "github.com/deckhouse/module-sdk/pkg" + "github.com/deckhouse/module-sdk/testing/mock" +) + +func TestReconcileSkipsWithoutModuleConfig(t *testing.T) { + values := mock.NewPatchableValuesCollectorMock(t) + values.GetMock.When("virtualization.internal.moduleConfig").Then(gjson.Result{}) + + input := &pkg.HookInput{Values: values} + if err := reconcile(conf)(context.Background(), input); err != nil { + t.Fatalf("expected nil error, got %v", err) + } +} diff --git a/images/hooks/pkg/hooks/tls-certificates-api/main.go b/images/hooks/pkg/hooks/tls-certificates-api/main.go index 0038bcf943..4ee97af5e4 100644 --- a/images/hooks/pkg/hooks/tls-certificates-api/main.go +++ b/images/hooks/pkg/hooks/tls-certificates-api/main.go @@ -17,13 +17,16 @@ limitations under the License. package tls_certificates_api import ( + "context" "fmt" tlscertificate "github.com/deckhouse/module-sdk/common-hooks/tls-certificate" + "github.com/deckhouse/module-sdk/pkg" + "github.com/deckhouse/module-sdk/pkg/registry" "github.com/deckhouse/virtualization/hooks/pkg/settings" ) -var _ = tlscertificate.RegisterInternalTLSHookEM(tlscertificate.GenSelfSignedTLSHookConf{ +var conf = tlscertificate.GenSelfSignedTLSHookConf{ CN: settings.APICertCN, TLSSecretName: "virtualization-api-tls", Namespace: settings.ModuleNamespace, @@ -40,4 +43,16 @@ var _ = tlscertificate.RegisterInternalTLSHookEM(tlscertificate.GenSelfSignedTLS FullValuesPathPrefix: fmt.Sprintf("%s.internal.apiserver.cert", settings.ModuleName), CommonCAValuesPath: fmt.Sprintf("%s.internal.rootCA", settings.ModuleName), -}) +} + +var reconcile = func(conf tlscertificate.GenSelfSignedTLSHookConf) pkg.ReconcileFunc { + return func(ctx context.Context, input *pkg.HookInput) error { + if !settings.HasModuleConfig(input) { + return nil + } + + return tlscertificate.GenSelfSignedTLS(conf)(ctx, input) + } +} + +var _ = registry.RegisterFunc(tlscertificate.GenSelfSignedTLSConfig(conf), reconcile(conf)) diff --git a/images/hooks/pkg/hooks/tls-certificates-api/main_test.go b/images/hooks/pkg/hooks/tls-certificates-api/main_test.go new file mode 100644 index 0000000000..a67ee6b909 --- /dev/null +++ b/images/hooks/pkg/hooks/tls-certificates-api/main_test.go @@ -0,0 +1,37 @@ +/* +Copyright 2026 Flant JSC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package tls_certificates_api + +import ( + "context" + "testing" + + "github.com/tidwall/gjson" + + "github.com/deckhouse/module-sdk/pkg" + "github.com/deckhouse/module-sdk/testing/mock" +) + +func TestReconcileSkipsWithoutModuleConfig(t *testing.T) { + values := mock.NewPatchableValuesCollectorMock(t) + values.GetMock.When("virtualization.internal.moduleConfig").Then(gjson.Result{}) + + input := &pkg.HookInput{Values: values} + if err := reconcile(conf)(context.Background(), input); err != nil { + t.Fatalf("expected nil error, got %v", err) + } +} diff --git a/images/hooks/pkg/hooks/tls-certificates-audit/hook.go b/images/hooks/pkg/hooks/tls-certificates-audit/hook.go index 105085e718..342e32cc19 100644 --- a/images/hooks/pkg/hooks/tls-certificates-audit/hook.go +++ b/images/hooks/pkg/hooks/tls-certificates-audit/hook.go @@ -41,6 +41,10 @@ var conf = tlscertificate.GenSelfSignedTLSHookConf{ var genSelfSignedTLS = func(conf tlscertificate.GenSelfSignedTLSHookConf) pkg.ReconcileFunc { return func(ctx context.Context, input *pkg.HookInput) error { + if !settings.HasModuleConfig(input) { + return nil + } + if !input.Values.Get("virtualization.audit.enabled").Bool() { return nil } diff --git a/images/hooks/pkg/hooks/tls-certificates-controller/hook.go b/images/hooks/pkg/hooks/tls-certificates-controller/hook.go index 37a174630b..3f16b5569a 100644 --- a/images/hooks/pkg/hooks/tls-certificates-controller/hook.go +++ b/images/hooks/pkg/hooks/tls-certificates-controller/hook.go @@ -17,13 +17,16 @@ limitations under the License. package tls_certificates_controller import ( + "context" "fmt" tlscertificate "github.com/deckhouse/module-sdk/common-hooks/tls-certificate" + "github.com/deckhouse/module-sdk/pkg" + "github.com/deckhouse/module-sdk/pkg/registry" "github.com/deckhouse/virtualization/hooks/pkg/settings" ) -var _ = tlscertificate.RegisterInternalTLSHookEM(tlscertificate.GenSelfSignedTLSHookConf{ +var conf = tlscertificate.GenSelfSignedTLSHookConf{ CN: settings.ControllerCertCN, TLSSecretName: "virtualization-controller-tls", Namespace: settings.ModuleNamespace, @@ -40,4 +43,16 @@ var _ = tlscertificate.RegisterInternalTLSHookEM(tlscertificate.GenSelfSignedTLS FullValuesPathPrefix: fmt.Sprintf("%s.internal.controller.cert", settings.ModuleName), CommonCAValuesPath: fmt.Sprintf("%s.internal.rootCA", settings.ModuleName), -}) +} + +var reconcile = func(conf tlscertificate.GenSelfSignedTLSHookConf) pkg.ReconcileFunc { + return func(ctx context.Context, input *pkg.HookInput) error { + if !settings.HasModuleConfig(input) { + return nil + } + + return tlscertificate.GenSelfSignedTLS(conf)(ctx, input) + } +} + +var _ = registry.RegisterFunc(tlscertificate.GenSelfSignedTLSConfig(conf), reconcile(conf)) diff --git a/images/hooks/pkg/hooks/tls-certificates-controller/hook_test.go b/images/hooks/pkg/hooks/tls-certificates-controller/hook_test.go new file mode 100644 index 0000000000..f3ef0ba2e3 --- /dev/null +++ b/images/hooks/pkg/hooks/tls-certificates-controller/hook_test.go @@ -0,0 +1,37 @@ +/* +Copyright 2026 Flant JSC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package tls_certificates_controller + +import ( + "context" + "testing" + + "github.com/tidwall/gjson" + + "github.com/deckhouse/module-sdk/pkg" + "github.com/deckhouse/module-sdk/testing/mock" +) + +func TestReconcileSkipsWithoutModuleConfig(t *testing.T) { + values := mock.NewPatchableValuesCollectorMock(t) + values.GetMock.When("virtualization.internal.moduleConfig").Then(gjson.Result{}) + + input := &pkg.HookInput{Values: values} + if err := reconcile(conf)(context.Background(), input); err != nil { + t.Fatalf("expected nil error, got %v", err) + } +} diff --git a/images/hooks/pkg/hooks/tls-certificates-dvcr/hook.go b/images/hooks/pkg/hooks/tls-certificates-dvcr/hook.go index 386157f26c..7284da6f9f 100644 --- a/images/hooks/pkg/hooks/tls-certificates-dvcr/hook.go +++ b/images/hooks/pkg/hooks/tls-certificates-dvcr/hook.go @@ -51,6 +51,10 @@ var _ = tlscertificate.RegisterInternalTLSHookEM(tlscertificate.GenSelfSignedTLS CommonCAValuesPath: fmt.Sprintf("%s.internal.rootCA", settings.ModuleName), BeforeHookCheck: func(input *pkg.HookInput) bool { + if !settings.HasModuleConfig(input) { + return false + } + return dvcrGetServiceIP(input).Type != gjson.Null }, }) diff --git a/images/hooks/pkg/hooks/tls-certificates-dvcr/hook_test.go b/images/hooks/pkg/hooks/tls-certificates-dvcr/hook_test.go new file mode 100644 index 0000000000..4c1bbaba87 --- /dev/null +++ b/images/hooks/pkg/hooks/tls-certificates-dvcr/hook_test.go @@ -0,0 +1,37 @@ +/* +Copyright 2026 Flant JSC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package tls_certificates_dvcr + +import ( + "testing" + + "github.com/tidwall/gjson" + + "github.com/deckhouse/module-sdk/pkg" + "github.com/deckhouse/module-sdk/testing/mock" + "github.com/deckhouse/virtualization/hooks/pkg/settings" +) + +func TestBeforeHookCheckSkipsWithoutModuleConfig(t *testing.T) { + values := mock.NewPatchableValuesCollectorMock(t) + values.GetMock.When(settings.InternalValuesConfigCopyPath).Then(gjson.Result{}) + + input := &pkg.HookInput{Values: values} + if settings.HasModuleConfig(input) { + t.Fatalf("expected copied module config to be absent") + } +} diff --git a/images/hooks/pkg/hooks/validate-module-config/hook.go b/images/hooks/pkg/hooks/validate-module-config/hook.go index c2a23ed13a..c6fbf9dee2 100644 --- a/images/hooks/pkg/hooks/validate-module-config/hook.go +++ b/images/hooks/pkg/hooks/validate-module-config/hook.go @@ -101,17 +101,22 @@ func Reconcile(_ context.Context, input *pkg.HookInput) error { input.Values.Set(settings.InternalValuesConfigValidationPath, map[string]string{ "error": fmt.Sprintf("ModuleConfig/virtualization is invalid: %v", err), }) - } else { - // Module is valid, remove moduleConfigValidation object to indicate valid state for the readiness probe. - input.Values.Remove(settings.InternalValuesConfigValidationPath) - // Copy valid settings from config values to apply them in helm templates. - copyModuleConfigSettingsIntoInternalValues(input) + return nil } + // Module is valid, remove moduleConfigValidation object to indicate valid state for the readiness probe. + input.Values.Remove(settings.InternalValuesConfigValidationPath) + // Copy valid settings from config values to apply them in helm templates. + copyModuleConfigSettingsIntoInternalValues(input) + return nil } func validateModuleConfigSettings(mc *mcapi.ModuleConfig, nodes []corev1.Node, podSubnet, serviceSubnet netip.Prefix) error { + if err := validateRequiredModuleConfigSettings(mc); err != nil { + return err + } + CIDRs, err := moduleconfig.ParseCIDRs(mc.Spec.Settings) if err != nil { return err @@ -147,6 +152,26 @@ func copyModuleConfigSettingsIntoInternalValues(input *pkg.HookInput) { input.Values.Set(settings.InternalValuesConfigCopyPath, cfg.Value()) } +func validateRequiredModuleConfigSettings(mc *mcapi.ModuleConfig) error { + if mc == nil { + return fmt.Errorf("moduleConfig is nil") + } + + if mc.Spec.Settings == nil { + return fmt.Errorf("spec.settings is empty") + } + + if _, ok := mc.Spec.Settings["virtualMachineCIDRs"]; !ok { + return fmt.Errorf("spec.settings.virtualMachineCIDRs is required") + } + + if _, ok := mc.Spec.Settings["dvcr"]; !ok { + return fmt.Errorf("spec.settings.dvcr is required") + } + + return nil +} + func moduleConfigFromSnapshot(input *pkg.HookInput) (*mcapi.ModuleConfig, error) { // Unmarshal ModuleConfig from jqFilter result. snap := input.Snapshots.Get(snapshotModuleConfig) diff --git a/images/hooks/pkg/hooks/validate-module-config/hook_test.go b/images/hooks/pkg/hooks/validate-module-config/hook_test.go index 2230d44cde..fa950ea89d 100644 --- a/images/hooks/pkg/hooks/validate-module-config/hook_test.go +++ b/images/hooks/pkg/hooks/validate-module-config/hook_test.go @@ -54,20 +54,32 @@ var _ = Describe("ModuleConfig validation hook", func() { "192.168.0.3", } - validVirtualMachineCIDRs = []interface{}{ + validVirtualMachineCIDRs = []any{ "10.33.0.0/24", "10.35.0.0/24", } - virtualMachineCIDRsOverlapWithNodeAddresses = []interface{}{ + validSettings = map[string]any{ + "virtualMachineCIDRs": validVirtualMachineCIDRs, + "dvcr": map[string]any{ + "storage": map[string]any{ + "type": "PersistentVolumeClaim", + "persistentVolumeClaim": map[string]any{ + "size": "10Gi", + }, + }, + }, + } + + virtualMachineCIDRsOverlapWithNodeAddresses = []any{ "192.168.0.0/24", "10.35.0.0/24", } - virtualMachineCIDRsOverlapWithPodSubnet = []interface{}{ + virtualMachineCIDRsOverlapWithPodSubnet = []any{ "10.108.0.0/14", "10.35.0.0/24", } - virtualMachineCIDRsOverlapWithServiceSubnet = []interface{}{ + virtualMachineCIDRsOverlapWithServiceSubnet = []any{ "10.220.0.0/14", "10.35.0.0/24", } @@ -78,12 +90,8 @@ var _ = Describe("ModuleConfig validation hook", func() { values.GetMock.When(serviceSubnetCIDRPath).Then(gjson.Result{Type: gjson.String, Str: serviceSubnet}) } - prepareConfigValues := func(cidrs []interface{}) { - cfgValues := map[string]interface{}{ - "virtualMachineCIDRs": cidrs, - } - cfgValuesBytes, _ := json.Marshal(cfgValues) - + prepareConfigValues := func(cfg map[string]any) { + cfgValuesBytes, _ := json.Marshal(cfg) configValues.GetMock.When("virtualization").Then(gjson.ParseBytes(cfgValuesBytes)) } @@ -92,7 +100,7 @@ var _ = Describe("ModuleConfig validation hook", func() { snapshots.GetMock.When(snapshotNodes).Then(nodes) } - newModuleConfigSnapshot := func(cidrs []interface{}) []pkg.Snapshot { + newModuleConfigSnapshot := func(settingsMap map[string]any) []pkg.Snapshot { return []pkg.Snapshot{ mock.NewSnapshotMock(GinkgoT()).UnmarshalToMock.Set(func(v any) (err error) { GinkgoHelper() @@ -100,12 +108,7 @@ var _ = Describe("ModuleConfig validation hook", func() { Expect(ok).To(BeTrue()) mc.SetName("virtualization") - - if cidrs != nil { - mc.Spec.Settings = map[string]interface{}{ - "virtualMachineCIDRs": cidrs, - } - } + mc.Spec.Settings = settingsMap return nil }), @@ -160,9 +163,9 @@ var _ = Describe("ModuleConfig validation hook", func() { It("Should copy moduleconfig settings into internal object if config is valid", func() { prepareValues(defaultPodSubnet, defaultServiceSubnet) - prepareConfigValues(validVirtualMachineCIDRs) + prepareConfigValues(validSettings) prepareSnapshots( - newModuleConfigSnapshot(validVirtualMachineCIDRs), + newModuleConfigSnapshot(validSettings), newNodesSnapshot(defaultNodeAddresses), ) @@ -170,6 +173,7 @@ var _ = Describe("ModuleConfig validation hook", func() { switch path { case settings.InternalValuesConfigCopyPath: Expect(v).To(HaveKey("virtualMachineCIDRs")) + Expect(v).To(HaveKey("dvcr")) case settings.InternalValuesConfigValidationPath: Fail("Should not set validation error") default: @@ -184,29 +188,79 @@ var _ = Describe("ModuleConfig validation hook", func() { Expect(Reconcile(context.Background(), newInput())).To(Succeed()) }) - DescribeTable("Should set validation error if virtualMachineCIDRs overlap with other addresses in cluster", func(cidrs []interface{}) { + DescribeTable("Should set validation error if settings are incomplete", func(settingsMap map[string]any, expectedError string) { prepareValues(defaultPodSubnet, defaultServiceSubnet) prepareSnapshots( - newModuleConfigSnapshot(cidrs), + newModuleConfigSnapshot(settingsMap), newNodesSnapshot(defaultNodeAddresses), ) + validationErrorSet := false + values.SetMock.Set(func(path string, v any) { switch path { case settings.InternalValuesConfigCopyPath: Fail("Should not copy ModuleConfig settings") case settings.InternalValuesConfigValidationPath: - Expect(v).To(HaveKey("error")) + validationErrorSet = true + obj, ok := v.(map[string]string) + Expect(ok).To(BeTrue()) + Expect(obj).To(HaveKey("error")) + Expect(obj["error"]).To(ContainSubstring(expectedError)) default: Fail("unexpected path") } }) - values.RemoveMock.Optional() + values.RemoveMock.Set(func(path string) { + if path == settings.InternalValuesConfigCopyPath { + Fail("Should not remove previous valid copied ModuleConfig") + } + }) Expect(Reconcile(context.Background(), newInput())).To(Succeed()) + Expect(validationErrorSet).To(BeTrue(), "should set validation error") + }, + Entry("settings are nil", nil, "spec.settings is empty"), + Entry("settings are empty", map[string]any{}, "spec.settings.virtualMachineCIDRs is required"), + Entry("dvcr is missing", map[string]any{ + "virtualMachineCIDRs": validVirtualMachineCIDRs, + }, "spec.settings.dvcr is required"), + ) - Expect(values.RemoveMock.Calls()).To(HaveLen(0), "should not remove values") + DescribeTable("Should set validation error if virtualMachineCIDRs overlap with other addresses in cluster", func(cidrs []any) { + prepareValues(defaultPodSubnet, defaultServiceSubnet) + invalidSettings := map[string]any{ + "virtualMachineCIDRs": cidrs, + "dvcr": validSettings["dvcr"], + } + prepareSnapshots( + newModuleConfigSnapshot(invalidSettings), + newNodesSnapshot(defaultNodeAddresses), + ) + + validationErrorSet := false + + values.SetMock.Set(func(path string, v any) { + switch path { + case settings.InternalValuesConfigCopyPath: + Fail("Should not copy ModuleConfig settings") + case settings.InternalValuesConfigValidationPath: + validationErrorSet = true + Expect(v).To(HaveKey("error")) + default: + Fail("unexpected path") + } + }) + values.RemoveMock.Optional() + values.RemoveMock.Set(func(path string) { + if path == settings.InternalValuesConfigCopyPath { + Fail("Should not remove previous valid copied ModuleConfig") + } + }) + + Expect(Reconcile(context.Background(), newInput())).To(Succeed()) + Expect(validationErrorSet).To(BeTrue(), "should set validation error") }, Entry("contain node address", virtualMachineCIDRsOverlapWithNodeAddresses), Entry("overlap with podSubnet", virtualMachineCIDRsOverlapWithPodSubnet), diff --git a/images/hooks/pkg/settings/module_config.go b/images/hooks/pkg/settings/module_config.go new file mode 100644 index 0000000000..6ce6b0b66b --- /dev/null +++ b/images/hooks/pkg/settings/module_config.go @@ -0,0 +1,32 @@ +/* +Copyright 2026 Flant JSC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package settings + +import "github.com/deckhouse/module-sdk/pkg" + +func HasModuleConfig(input *pkg.HookInput) bool { + config := input.Values.Get(InternalValuesConfigCopyPath) + if !config.Exists() { + return false + } + + if !config.IsObject() { + return false + } + + return len(config.Map()) > 0 +} diff --git a/images/hooks/pkg/settings/module_config_test.go b/images/hooks/pkg/settings/module_config_test.go new file mode 100644 index 0000000000..7ce016ac6b --- /dev/null +++ b/images/hooks/pkg/settings/module_config_test.go @@ -0,0 +1,68 @@ +/* +Copyright 2026 Flant JSC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package settings + +import ( + "testing" + + "github.com/tidwall/gjson" + + "github.com/deckhouse/module-sdk/pkg" + "github.com/deckhouse/module-sdk/testing/mock" +) + +func TestHasModuleConfig(t *testing.T) { + newInput := func(values *mock.OutputPatchableValuesCollectorMock) *pkg.HookInput { + return &pkg.HookInput{Values: values} + } + + t.Run("returns false when moduleConfig is absent", func(t *testing.T) { + values := mock.NewPatchableValuesCollectorMock(t) + values.GetMock.When(InternalValuesConfigCopyPath).Then(gjson.Result{}) + + if HasModuleConfig(newInput(values)) { + t.Fatalf("expected HasModuleConfig to return false") + } + }) + + t.Run("returns false when moduleConfig is not an object", func(t *testing.T) { + values := mock.NewPatchableValuesCollectorMock(t) + values.GetMock.When(InternalValuesConfigCopyPath).Then(gjson.Result{Type: gjson.String, Str: "value"}) + + if HasModuleConfig(newInput(values)) { + t.Fatalf("expected HasModuleConfig to return false") + } + }) + + t.Run("returns false when moduleConfig is an empty object", func(t *testing.T) { + values := mock.NewPatchableValuesCollectorMock(t) + values.GetMock.When(InternalValuesConfigCopyPath).Then(gjson.Parse(`{}`)) + + if HasModuleConfig(newInput(values)) { + t.Fatalf("expected HasModuleConfig to return false") + } + }) + + t.Run("returns true when moduleConfig is a non-empty object", func(t *testing.T) { + values := mock.NewPatchableValuesCollectorMock(t) + values.GetMock.When(InternalValuesConfigCopyPath).Then(gjson.Parse(`{"dvcr":{},"virtualMachineCIDRs":["10.0.0.0/24"]}`)) + + if !HasModuleConfig(newInput(values)) { + t.Fatalf("expected HasModuleConfig to return true") + } + }) +} diff --git a/templates/_helpers.tpl b/templates/_helpers.tpl index 6564d55cde..1a56e5988a 100644 --- a/templates/_helpers.tpl +++ b/templates/_helpers.tpl @@ -62,7 +62,7 @@ nodeSelector: {{- end }} {{- define "hasValidModuleConfig" -}} -{{- if (hasKey .Values.virtualization.internal "moduleConfig" ) -}} +{{- if (hasKey .Values.virtualization.internal "moduleConfig") -}} true {{- end }} {{- end }} From 25113c99dd67ded1a559405cf8f34c0ac3cbb436 Mon Sep 17 00:00:00 2001 From: Dmitry Lopatin Date: Tue, 21 Apr 2026 13:54:30 +0300 Subject: [PATCH 2/7] after review Signed-off-by: Dmitry Lopatin --- .../hook.go | 8 +- .../hook_test.go | 9 +- .../test_helpers_test.go | 33 ++++++ .../hooks/discovery-workload-nodes/hook.go | 8 +- .../discovery-workload-nodes/hook_test.go | 38 +++++-- .../hooks/generate-secret-for-dvcr/hook.go | 8 +- .../generate-secret-for-dvcr/hook_test.go | 9 +- .../test_helpers_test.go | 33 ++++++ .../hooks/tls-certificates-api-proxy/main.go | 6 +- .../tls-certificates-api-proxy/main_test.go | 26 +++-- .../pkg/hooks/tls-certificates-api/main.go | 6 +- .../hooks/tls-certificates-api/main_test.go | 26 +++-- .../pkg/hooks/tls-certificates-audit/hook.go | 6 +- .../hooks/tls-certificates-controller/hook.go | 6 +- .../tls-certificates-controller/hook_test.go | 26 +++-- .../pkg/hooks/tls-certificates-dvcr/hook.go | 8 +- .../hooks/tls-certificates-dvcr/hook_test.go | 33 ++++-- images/hooks/pkg/settings/module_config.go | 59 ++++++++-- .../hooks/pkg/settings/module_config_test.go | 101 ++++++++++++++---- 19 files changed, 373 insertions(+), 76 deletions(-) create mode 100644 images/hooks/pkg/hooks/discovery-clusterip-service-for-dvcr/test_helpers_test.go create mode 100644 images/hooks/pkg/hooks/generate-secret-for-dvcr/test_helpers_test.go diff --git a/images/hooks/pkg/hooks/discovery-clusterip-service-for-dvcr/hook.go b/images/hooks/pkg/hooks/discovery-clusterip-service-for-dvcr/hook.go index 411e602cd3..91aa66f0f4 100644 --- a/images/hooks/pkg/hooks/discovery-clusterip-service-for-dvcr/hook.go +++ b/images/hooks/pkg/hooks/discovery-clusterip-service-for-dvcr/hook.go @@ -64,8 +64,12 @@ var configDiscoveryService = &pkg.HookConfig{ Queue: fmt.Sprintf("modules/%s", settings.ModuleName), } -func handleDiscoveryService(_ context.Context, input *pkg.HookInput) error { - if !settings.HasModuleConfig(input) { +func handleDiscoveryService(ctx context.Context, input *pkg.HookInput) error { + hasModuleConfig, err := settings.HasModuleConfig(ctx, input) + if err != nil { + return err + } + if !hasModuleConfig { return nil } diff --git a/images/hooks/pkg/hooks/discovery-clusterip-service-for-dvcr/hook_test.go b/images/hooks/pkg/hooks/discovery-clusterip-service-for-dvcr/hook_test.go index 4d289aeffc..3d1a2cb02d 100644 --- a/images/hooks/pkg/hooks/discovery-clusterip-service-for-dvcr/hook_test.go +++ b/images/hooks/pkg/hooks/discovery-clusterip-service-for-dvcr/hook_test.go @@ -23,10 +23,13 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/tidwall/gjson" + ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" "github.com/deckhouse/deckhouse/pkg/log" "github.com/deckhouse/module-sdk/pkg" "github.com/deckhouse/module-sdk/testing/mock" + mcapi "github.com/deckhouse/virtualization-controller/pkg/controller/moduleconfig/api" + "github.com/deckhouse/virtualization/hooks/pkg/settings" ) func TestDiscoveryClusterIPServiceForDVCR(t *testing.T) { @@ -64,7 +67,11 @@ var _ = Describe("DiscoveryClusterIPServiceForDVCR", func() { } newInput := func() *pkg.HookInput { - values.GetMock.When("virtualization.internal.moduleConfig").Then(gjson.Parse(`{"dvcr":{},"virtualMachineCIDRs":["10.0.0.0/24"]}`)) + dc.GetK8sClientMock.Return(&fakeKubernetesClient{get: func(ctx context.Context, key ctrlclient.ObjectKey, obj ctrlclient.Object) error { + mc := obj.(*mcapi.ModuleConfig) + *mc = *settings.NewModuleConfigForTest(map[string]any{"dvcr": map[string]any{}, "virtualMachineCIDRs": []any{"10.0.0.0/24"}}) + return nil + }}, nil) return &pkg.HookInput{ Snapshots: snapshots, Values: values, diff --git a/images/hooks/pkg/hooks/discovery-clusterip-service-for-dvcr/test_helpers_test.go b/images/hooks/pkg/hooks/discovery-clusterip-service-for-dvcr/test_helpers_test.go new file mode 100644 index 0000000000..d7472e67a8 --- /dev/null +++ b/images/hooks/pkg/hooks/discovery-clusterip-service-for-dvcr/test_helpers_test.go @@ -0,0 +1,33 @@ +/* +Copyright 2026 Flant JSC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package discovery_clusterip_service_for_dvcr + +import ( + "context" + + "github.com/deckhouse/module-sdk/pkg" + ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" +) + +type fakeKubernetesClient struct { + pkg.KubernetesClient + get func(ctx context.Context, key ctrlclient.ObjectKey, obj ctrlclient.Object) error +} + +func (f *fakeKubernetesClient) Get(ctx context.Context, key ctrlclient.ObjectKey, obj ctrlclient.Object, _ ...ctrlclient.GetOption) error { + return f.get(ctx, key, obj) +} diff --git a/images/hooks/pkg/hooks/discovery-workload-nodes/hook.go b/images/hooks/pkg/hooks/discovery-workload-nodes/hook.go index ec35fbcee7..775819914b 100644 --- a/images/hooks/pkg/hooks/discovery-workload-nodes/hook.go +++ b/images/hooks/pkg/hooks/discovery-workload-nodes/hook.go @@ -78,8 +78,12 @@ var configDiscoveryService = &pkg.HookConfig{ Queue: fmt.Sprintf("modules/%s", settings.ModuleName), } -func handleDiscoveryNodes(_ context.Context, input *pkg.HookInput) error { - if !settings.HasModuleConfig(input) { +func handleDiscoveryNodes(ctx context.Context, input *pkg.HookInput) error { + hasModuleConfig, err := settings.HasModuleConfig(ctx, input) + if err != nil { + return err + } + if !hasModuleConfig { return nil } diff --git a/images/hooks/pkg/hooks/discovery-workload-nodes/hook_test.go b/images/hooks/pkg/hooks/discovery-workload-nodes/hook_test.go index de0cf28ce5..91ede8638e 100644 --- a/images/hooks/pkg/hooks/discovery-workload-nodes/hook_test.go +++ b/images/hooks/pkg/hooks/discovery-workload-nodes/hook_test.go @@ -22,11 +22,13 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - "github.com/tidwall/gjson" + ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" "github.com/deckhouse/deckhouse/pkg/log" "github.com/deckhouse/module-sdk/pkg" "github.com/deckhouse/module-sdk/testing/mock" + mcapi "github.com/deckhouse/virtualization-controller/pkg/controller/moduleconfig/api" + "github.com/deckhouse/virtualization/hooks/pkg/settings" ) func TestDiscoveryWorkloadNodes(t *testing.T) { @@ -34,14 +36,34 @@ func TestDiscoveryWorkloadNodes(t *testing.T) { RunSpecs(t, "DiscoveryWorkloadNodes Suite") } +type fakeKubernetesClient struct { + pkg.KubernetesClient + get func(ctx context.Context, key ctrlclient.ObjectKey, obj ctrlclient.Object) error +} + +func (f *fakeKubernetesClient) Get(ctx context.Context, key ctrlclient.ObjectKey, obj ctrlclient.Object, _ ...ctrlclient.GetOption) error { + return f.get(ctx, key, obj) +} + var _ = Describe("DiscoveryWorkloadNodes", func() { var ( + dc *mock.DependencyContainerMock snapshots *mock.SnapshotsMock values *mock.OutputPatchableValuesCollectorMock ) - newInput := func() *pkg.HookInput { + newInput := func(withModuleConfig bool) *pkg.HookInput { + dc.GetK8sClientMock.Return(&fakeKubernetesClient{get: func(ctx context.Context, key ctrlclient.ObjectKey, obj ctrlclient.Object) error { + mc := obj.(*mcapi.ModuleConfig) + if withModuleConfig { + *mc = *settings.NewModuleConfigForTest(map[string]any{"dvcr": map[string]any{}, "virtualMachineCIDRs": []any{"10.0.0.0/24"}}) + } else { + *mc = *settings.NewModuleConfigForTest(nil) + } + return nil + }}, nil) return &pkg.HookInput{ + DC: dc, Snapshots: snapshots, Values: values, Logger: log.NewNop(), @@ -49,22 +71,22 @@ var _ = Describe("DiscoveryWorkloadNodes", func() { } BeforeEach(func() { + dc = mock.NewDependencyContainerMock(GinkgoT()) snapshots = mock.NewSnapshotsMock(GinkgoT()) values = mock.NewPatchableValuesCollectorMock(GinkgoT()) }) AfterEach(func() { + dc = nil snapshots = nil values = nil }) - It("should do nothing when copied module config is absent", func() { - values.GetMock.When("virtualization.internal.moduleConfig").Then(gjson.Result{}) - Expect(handleDiscoveryNodes(context.Background(), newInput())).To(Succeed()) + It("should do nothing when module config is incomplete", func() { + Expect(handleDiscoveryNodes(context.Background(), newInput(false))).To(Succeed()) }) - It("should set node count when copied module config exists", func() { - values.GetMock.When("virtualization.internal.moduleConfig").Then(gjson.Parse(`{"dvcr":{},"virtualMachineCIDRs":["10.0.0.0/24"]}`)) + It("should set node count when module config exists", func() { snapshots.GetMock.When(discoveryNodesSnapshot).Then([]pkg.Snapshot{ mock.NewSnapshotMock(GinkgoT()), mock.NewSnapshotMock(GinkgoT()), @@ -78,7 +100,7 @@ var _ = Describe("DiscoveryWorkloadNodes", func() { Expect(v).To(Equal(2)) }) - Expect(handleDiscoveryNodes(context.Background(), newInput())).To(Succeed()) + Expect(handleDiscoveryNodes(context.Background(), newInput(true))).To(Succeed()) Expect(setCalls).To(Equal(1)) }) }) diff --git a/images/hooks/pkg/hooks/generate-secret-for-dvcr/hook.go b/images/hooks/pkg/hooks/generate-secret-for-dvcr/hook.go index 1fb2ce9521..b68ce8de42 100644 --- a/images/hooks/pkg/hooks/generate-secret-for-dvcr/hook.go +++ b/images/hooks/pkg/hooks/generate-secret-for-dvcr/hook.go @@ -73,8 +73,12 @@ var configDVCRSecrets = &pkg.HookConfig{ Queue: fmt.Sprintf("modules/%s", settings.ModuleName), } -func handlerDVCRSecrets(_ context.Context, input *pkg.HookInput) error { - if !settings.HasModuleConfig(input) { +func handlerDVCRSecrets(ctx context.Context, input *pkg.HookInput) error { + hasModuleConfig, err := settings.HasModuleConfig(ctx, input) + if err != nil { + return err + } + if !hasModuleConfig { return nil } diff --git a/images/hooks/pkg/hooks/generate-secret-for-dvcr/hook_test.go b/images/hooks/pkg/hooks/generate-secret-for-dvcr/hook_test.go index b08180e2dd..2874c38414 100644 --- a/images/hooks/pkg/hooks/generate-secret-for-dvcr/hook_test.go +++ b/images/hooks/pkg/hooks/generate-secret-for-dvcr/hook_test.go @@ -24,10 +24,13 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/tidwall/gjson" + ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" "github.com/deckhouse/deckhouse/pkg/log" "github.com/deckhouse/module-sdk/pkg" "github.com/deckhouse/module-sdk/testing/mock" + mcapi "github.com/deckhouse/virtualization-controller/pkg/controller/moduleconfig/api" + "github.com/deckhouse/virtualization/hooks/pkg/settings" ) func TestSetDVCRSecrets(t *testing.T) { @@ -70,7 +73,11 @@ var _ = Describe("DVCR Secrets", func() { } newInput := func() *pkg.HookInput { - values.GetMock.When("virtualization.internal.moduleConfig").Then(gjson.Parse(`{"dvcr":{},"virtualMachineCIDRs":["10.0.0.0/24"]}`)) + dc.GetK8sClientMock.Return(&fakeKubernetesClient{get: func(ctx context.Context, key ctrlclient.ObjectKey, obj ctrlclient.Object) error { + mc := obj.(*mcapi.ModuleConfig) + *mc = *settings.NewModuleConfigForTest(map[string]any{"dvcr": map[string]any{}, "virtualMachineCIDRs": []any{"10.0.0.0/24"}}) + return nil + }}, nil) return &pkg.HookInput{ Snapshots: snapshots, Values: values, diff --git a/images/hooks/pkg/hooks/generate-secret-for-dvcr/test_helpers_test.go b/images/hooks/pkg/hooks/generate-secret-for-dvcr/test_helpers_test.go new file mode 100644 index 0000000000..8838fc8edb --- /dev/null +++ b/images/hooks/pkg/hooks/generate-secret-for-dvcr/test_helpers_test.go @@ -0,0 +1,33 @@ +/* +Copyright 2026 Flant JSC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package generate_secret_for_dvcr + +import ( + "context" + + "github.com/deckhouse/module-sdk/pkg" + ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" +) + +type fakeKubernetesClient struct { + pkg.KubernetesClient + get func(ctx context.Context, key ctrlclient.ObjectKey, obj ctrlclient.Object) error +} + +func (f *fakeKubernetesClient) Get(ctx context.Context, key ctrlclient.ObjectKey, obj ctrlclient.Object, _ ...ctrlclient.GetOption) error { + return f.get(ctx, key, obj) +} diff --git a/images/hooks/pkg/hooks/tls-certificates-api-proxy/main.go b/images/hooks/pkg/hooks/tls-certificates-api-proxy/main.go index 0145edcea2..fa98fc912d 100644 --- a/images/hooks/pkg/hooks/tls-certificates-api-proxy/main.go +++ b/images/hooks/pkg/hooks/tls-certificates-api-proxy/main.go @@ -40,7 +40,11 @@ var conf = tlscertificate.GenSelfSignedTLSHookConf{ var reconcile = func(conf tlscertificate.GenSelfSignedTLSHookConf) pkg.ReconcileFunc { return func(ctx context.Context, input *pkg.HookInput) error { - if !settings.HasModuleConfig(input) { + hasModuleConfig, err := settings.HasModuleConfig(ctx, input) + if err != nil { + return err + } + if !hasModuleConfig { return nil } diff --git a/images/hooks/pkg/hooks/tls-certificates-api-proxy/main_test.go b/images/hooks/pkg/hooks/tls-certificates-api-proxy/main_test.go index 5f0d4955f6..6318568aed 100644 --- a/images/hooks/pkg/hooks/tls-certificates-api-proxy/main_test.go +++ b/images/hooks/pkg/hooks/tls-certificates-api-proxy/main_test.go @@ -20,17 +20,31 @@ import ( "context" "testing" - "github.com/tidwall/gjson" - "github.com/deckhouse/module-sdk/pkg" "github.com/deckhouse/module-sdk/testing/mock" + mcapi "github.com/deckhouse/virtualization-controller/pkg/controller/moduleconfig/api" + "github.com/deckhouse/virtualization/hooks/pkg/settings" + ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" ) -func TestReconcileSkipsWithoutModuleConfig(t *testing.T) { - values := mock.NewPatchableValuesCollectorMock(t) - values.GetMock.When("virtualization.internal.moduleConfig").Then(gjson.Result{}) +type fakeKubernetesClient struct { + pkg.KubernetesClient + get func(ctx context.Context, key ctrlclient.ObjectKey, obj ctrlclient.Object) error +} - input := &pkg.HookInput{Values: values} +func (f *fakeKubernetesClient) Get(ctx context.Context, key ctrlclient.ObjectKey, obj ctrlclient.Object, _ ...ctrlclient.GetOption) error { + return f.get(ctx, key, obj) +} + +func TestReconcileSkipsWithoutModuleConfig(t *testing.T) { + dc := mock.NewDependencyContainerMock(t) + dc.GetK8sClientMock.Return(&fakeKubernetesClient{get: func(ctx context.Context, key ctrlclient.ObjectKey, obj ctrlclient.Object) error { + mc := obj.(*mcapi.ModuleConfig) + *mc = *settings.NewModuleConfigForTest(nil) + return nil + }}, nil) + + input := &pkg.HookInput{DC: dc} if err := reconcile(conf)(context.Background(), input); err != nil { t.Fatalf("expected nil error, got %v", err) } diff --git a/images/hooks/pkg/hooks/tls-certificates-api/main.go b/images/hooks/pkg/hooks/tls-certificates-api/main.go index 4ee97af5e4..cb83d857c6 100644 --- a/images/hooks/pkg/hooks/tls-certificates-api/main.go +++ b/images/hooks/pkg/hooks/tls-certificates-api/main.go @@ -47,7 +47,11 @@ var conf = tlscertificate.GenSelfSignedTLSHookConf{ var reconcile = func(conf tlscertificate.GenSelfSignedTLSHookConf) pkg.ReconcileFunc { return func(ctx context.Context, input *pkg.HookInput) error { - if !settings.HasModuleConfig(input) { + hasModuleConfig, err := settings.HasModuleConfig(ctx, input) + if err != nil { + return err + } + if !hasModuleConfig { return nil } diff --git a/images/hooks/pkg/hooks/tls-certificates-api/main_test.go b/images/hooks/pkg/hooks/tls-certificates-api/main_test.go index a67ee6b909..a8392f6c5d 100644 --- a/images/hooks/pkg/hooks/tls-certificates-api/main_test.go +++ b/images/hooks/pkg/hooks/tls-certificates-api/main_test.go @@ -20,17 +20,31 @@ import ( "context" "testing" - "github.com/tidwall/gjson" - "github.com/deckhouse/module-sdk/pkg" "github.com/deckhouse/module-sdk/testing/mock" + mcapi "github.com/deckhouse/virtualization-controller/pkg/controller/moduleconfig/api" + "github.com/deckhouse/virtualization/hooks/pkg/settings" + ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" ) -func TestReconcileSkipsWithoutModuleConfig(t *testing.T) { - values := mock.NewPatchableValuesCollectorMock(t) - values.GetMock.When("virtualization.internal.moduleConfig").Then(gjson.Result{}) +type fakeKubernetesClient struct { + pkg.KubernetesClient + get func(ctx context.Context, key ctrlclient.ObjectKey, obj ctrlclient.Object) error +} - input := &pkg.HookInput{Values: values} +func (f *fakeKubernetesClient) Get(ctx context.Context, key ctrlclient.ObjectKey, obj ctrlclient.Object, _ ...ctrlclient.GetOption) error { + return f.get(ctx, key, obj) +} + +func TestReconcileSkipsWithoutModuleConfig(t *testing.T) { + dc := mock.NewDependencyContainerMock(t) + dc.GetK8sClientMock.Return(&fakeKubernetesClient{get: func(ctx context.Context, key ctrlclient.ObjectKey, obj ctrlclient.Object) error { + mc := obj.(*mcapi.ModuleConfig) + *mc = *settings.NewModuleConfigForTest(nil) + return nil + }}, nil) + + input := &pkg.HookInput{DC: dc} if err := reconcile(conf)(context.Background(), input); err != nil { t.Fatalf("expected nil error, got %v", err) } diff --git a/images/hooks/pkg/hooks/tls-certificates-audit/hook.go b/images/hooks/pkg/hooks/tls-certificates-audit/hook.go index 342e32cc19..5c547a3090 100644 --- a/images/hooks/pkg/hooks/tls-certificates-audit/hook.go +++ b/images/hooks/pkg/hooks/tls-certificates-audit/hook.go @@ -41,7 +41,11 @@ var conf = tlscertificate.GenSelfSignedTLSHookConf{ var genSelfSignedTLS = func(conf tlscertificate.GenSelfSignedTLSHookConf) pkg.ReconcileFunc { return func(ctx context.Context, input *pkg.HookInput) error { - if !settings.HasModuleConfig(input) { + hasModuleConfig, err := settings.HasModuleConfig(ctx, input) + if err != nil { + return err + } + if !hasModuleConfig { return nil } diff --git a/images/hooks/pkg/hooks/tls-certificates-controller/hook.go b/images/hooks/pkg/hooks/tls-certificates-controller/hook.go index 3f16b5569a..50fe56b3f5 100644 --- a/images/hooks/pkg/hooks/tls-certificates-controller/hook.go +++ b/images/hooks/pkg/hooks/tls-certificates-controller/hook.go @@ -47,7 +47,11 @@ var conf = tlscertificate.GenSelfSignedTLSHookConf{ var reconcile = func(conf tlscertificate.GenSelfSignedTLSHookConf) pkg.ReconcileFunc { return func(ctx context.Context, input *pkg.HookInput) error { - if !settings.HasModuleConfig(input) { + hasModuleConfig, err := settings.HasModuleConfig(ctx, input) + if err != nil { + return err + } + if !hasModuleConfig { return nil } diff --git a/images/hooks/pkg/hooks/tls-certificates-controller/hook_test.go b/images/hooks/pkg/hooks/tls-certificates-controller/hook_test.go index f3ef0ba2e3..6153f135e6 100644 --- a/images/hooks/pkg/hooks/tls-certificates-controller/hook_test.go +++ b/images/hooks/pkg/hooks/tls-certificates-controller/hook_test.go @@ -20,17 +20,31 @@ import ( "context" "testing" - "github.com/tidwall/gjson" - "github.com/deckhouse/module-sdk/pkg" "github.com/deckhouse/module-sdk/testing/mock" + mcapi "github.com/deckhouse/virtualization-controller/pkg/controller/moduleconfig/api" + "github.com/deckhouse/virtualization/hooks/pkg/settings" + ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" ) -func TestReconcileSkipsWithoutModuleConfig(t *testing.T) { - values := mock.NewPatchableValuesCollectorMock(t) - values.GetMock.When("virtualization.internal.moduleConfig").Then(gjson.Result{}) +type fakeKubernetesClient struct { + pkg.KubernetesClient + get func(ctx context.Context, key ctrlclient.ObjectKey, obj ctrlclient.Object) error +} - input := &pkg.HookInput{Values: values} +func (f *fakeKubernetesClient) Get(ctx context.Context, key ctrlclient.ObjectKey, obj ctrlclient.Object, _ ...ctrlclient.GetOption) error { + return f.get(ctx, key, obj) +} + +func TestReconcileSkipsWithoutModuleConfig(t *testing.T) { + dc := mock.NewDependencyContainerMock(t) + dc.GetK8sClientMock.Return(&fakeKubernetesClient{get: func(ctx context.Context, key ctrlclient.ObjectKey, obj ctrlclient.Object) error { + mc := obj.(*mcapi.ModuleConfig) + *mc = *settings.NewModuleConfigForTest(nil) + return nil + }}, nil) + + input := &pkg.HookInput{DC: dc} if err := reconcile(conf)(context.Background(), input); err != nil { t.Fatalf("expected nil error, got %v", err) } diff --git a/images/hooks/pkg/hooks/tls-certificates-dvcr/hook.go b/images/hooks/pkg/hooks/tls-certificates-dvcr/hook.go index 7284da6f9f..2bee3ac415 100644 --- a/images/hooks/pkg/hooks/tls-certificates-dvcr/hook.go +++ b/images/hooks/pkg/hooks/tls-certificates-dvcr/hook.go @@ -17,6 +17,7 @@ limitations under the License. package tls_certificates_dvcr import ( + "context" "fmt" "github.com/tidwall/gjson" @@ -51,7 +52,12 @@ var _ = tlscertificate.RegisterInternalTLSHookEM(tlscertificate.GenSelfSignedTLS CommonCAValuesPath: fmt.Sprintf("%s.internal.rootCA", settings.ModuleName), BeforeHookCheck: func(input *pkg.HookInput) bool { - if !settings.HasModuleConfig(input) { + hasModuleConfig, err := settings.HasModuleConfig(context.Background(), input) + if err != nil { + input.Logger.Error("Check module config before DVCR TLS hook", "error", err) + return false + } + if !hasModuleConfig { return false } diff --git a/images/hooks/pkg/hooks/tls-certificates-dvcr/hook_test.go b/images/hooks/pkg/hooks/tls-certificates-dvcr/hook_test.go index 4c1bbaba87..43dd9a96ae 100644 --- a/images/hooks/pkg/hooks/tls-certificates-dvcr/hook_test.go +++ b/images/hooks/pkg/hooks/tls-certificates-dvcr/hook_test.go @@ -17,21 +17,38 @@ limitations under the License. package tls_certificates_dvcr import ( + "context" "testing" - "github.com/tidwall/gjson" - "github.com/deckhouse/module-sdk/pkg" "github.com/deckhouse/module-sdk/testing/mock" + mcapi "github.com/deckhouse/virtualization-controller/pkg/controller/moduleconfig/api" "github.com/deckhouse/virtualization/hooks/pkg/settings" + ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" ) -func TestBeforeHookCheckSkipsWithoutModuleConfig(t *testing.T) { - values := mock.NewPatchableValuesCollectorMock(t) - values.GetMock.When(settings.InternalValuesConfigCopyPath).Then(gjson.Result{}) +type fakeKubernetesClient struct { + pkg.KubernetesClient + get func(ctx context.Context, key ctrlclient.ObjectKey, obj ctrlclient.Object) error +} - input := &pkg.HookInput{Values: values} - if settings.HasModuleConfig(input) { - t.Fatalf("expected copied module config to be absent") +func (f *fakeKubernetesClient) Get(ctx context.Context, key ctrlclient.ObjectKey, obj ctrlclient.Object, _ ...ctrlclient.GetOption) error { + return f.get(ctx, key, obj) +} + +func TestBeforeHookCheckSkipsWithoutModuleConfig(t *testing.T) { + dc := mock.NewDependencyContainerMock(t) + dc.GetK8sClientMock.Return(&fakeKubernetesClient{get: func(ctx context.Context, key ctrlclient.ObjectKey, obj ctrlclient.Object) error { + mc := obj.(*mcapi.ModuleConfig) + *mc = *settings.NewModuleConfigForTest(nil) + return nil + }}, nil) + + ok, err := settings.HasModuleConfig(context.Background(), &pkg.HookInput{DC: dc}) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if ok { + t.Fatalf("expected module config check to return false") } } diff --git a/images/hooks/pkg/settings/module_config.go b/images/hooks/pkg/settings/module_config.go index 6ce6b0b66b..6b79dfc5f9 100644 --- a/images/hooks/pkg/settings/module_config.go +++ b/images/hooks/pkg/settings/module_config.go @@ -16,17 +16,60 @@ limitations under the License. package settings -import "github.com/deckhouse/module-sdk/pkg" +import ( + "context" + "fmt" -func HasModuleConfig(input *pkg.HookInput) bool { - config := input.Values.Get(InternalValuesConfigCopyPath) - if !config.Exists() { - return false + "github.com/deckhouse/module-sdk/pkg" + mcapi "github.com/deckhouse/virtualization-controller/pkg/controller/moduleconfig/api" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +func HasModuleConfig(ctx context.Context, input *pkg.HookInput) (bool, error) { + if input == nil || input.DC == nil { + return false, fmt.Errorf("dependency container is nil") + } + + k8sClient, err := input.DC.GetK8sClient() + if err != nil { + return false, fmt.Errorf("get kubernetes client: %w", err) + } + + var moduleConfig mcapi.ModuleConfig + err = k8sClient.Get(ctx, client.ObjectKey{Name: ModuleName}, &moduleConfig) + if err != nil { + if apierrors.IsNotFound(err) { + return false, nil + } + return false, fmt.Errorf("get ModuleConfig/%s: %w", ModuleName, err) + } + + if moduleConfig.Spec.Settings == nil { + return false, nil + } + + if _, ok := moduleConfig.Spec.Settings["virtualMachineCIDRs"]; !ok { + return false, nil } - if !config.IsObject() { - return false + if _, ok := moduleConfig.Spec.Settings["dvcr"]; !ok { + return false, nil } - return len(config.Map()) > 0 + return true, nil +} + +func NewModuleConfigForTest(settings map[string]any) *mcapi.ModuleConfig { + return &mcapi.ModuleConfig{ + TypeMeta: metav1.TypeMeta{ + Kind: "ModuleConfig", + APIVersion: "deckhouse.io/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{Name: ModuleName}, + Spec: mcapi.ModuleConfigSpec{ + Settings: settings, + }, + } } diff --git a/images/hooks/pkg/settings/module_config_test.go b/images/hooks/pkg/settings/module_config_test.go index 7ce016ac6b..4a69ef3b1b 100644 --- a/images/hooks/pkg/settings/module_config_test.go +++ b/images/hooks/pkg/settings/module_config_test.go @@ -17,52 +17,111 @@ limitations under the License. package settings import ( + "context" "testing" - "github.com/tidwall/gjson" - "github.com/deckhouse/module-sdk/pkg" "github.com/deckhouse/module-sdk/testing/mock" + mcapi "github.com/deckhouse/virtualization-controller/pkg/controller/moduleconfig/api" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime/schema" + ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" ) +type fakeKubernetesClient struct { + pkg.KubernetesClient + get func(ctx context.Context, key ctrlclient.ObjectKey, obj ctrlclient.Object) error +} + +func (f *fakeKubernetesClient) Get(ctx context.Context, key ctrlclient.ObjectKey, obj ctrlclient.Object, _ ...ctrlclient.GetOption) error { + return f.get(ctx, key, obj) +} + func TestHasModuleConfig(t *testing.T) { - newInput := func(values *mock.OutputPatchableValuesCollectorMock) *pkg.HookInput { - return &pkg.HookInput{Values: values} + newInput := func(client pkg.KubernetesClient, err error) *pkg.HookInput { + dc := mock.NewDependencyContainerMock(t) + dc.GetK8sClientMock.Return(client, err) + return &pkg.HookInput{DC: dc} } - t.Run("returns false when moduleConfig is absent", func(t *testing.T) { - values := mock.NewPatchableValuesCollectorMock(t) - values.GetMock.When(InternalValuesConfigCopyPath).Then(gjson.Result{}) + t.Run("returns false when module config does not exist", func(t *testing.T) { + input := newInput(&fakeKubernetesClient{get: func(ctx context.Context, key ctrlclient.ObjectKey, obj ctrlclient.Object) error { + return apierrors.NewNotFound(schema.GroupResource{Group: "deckhouse.io", Resource: "moduleconfigs"}, ModuleName) + }}, nil) - if HasModuleConfig(newInput(values)) { + ok, err := HasModuleConfig(context.Background(), input) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if ok { t.Fatalf("expected HasModuleConfig to return false") } }) - t.Run("returns false when moduleConfig is not an object", func(t *testing.T) { - values := mock.NewPatchableValuesCollectorMock(t) - values.GetMock.When(InternalValuesConfigCopyPath).Then(gjson.Result{Type: gjson.String, Str: "value"}) + t.Run("returns false when settings are nil", func(t *testing.T) { + input := newInput(&fakeKubernetesClient{get: func(ctx context.Context, key ctrlclient.ObjectKey, obj ctrlclient.Object) error { + mc := obj.(*mcapi.ModuleConfig) + *mc = *NewModuleConfigForTest(nil) + return nil + }}, nil) - if HasModuleConfig(newInput(values)) { + ok, err := HasModuleConfig(context.Background(), input) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if ok { t.Fatalf("expected HasModuleConfig to return false") } }) - t.Run("returns false when moduleConfig is an empty object", func(t *testing.T) { - values := mock.NewPatchableValuesCollectorMock(t) - values.GetMock.When(InternalValuesConfigCopyPath).Then(gjson.Parse(`{}`)) + t.Run("returns false when required settings are absent", func(t *testing.T) { + input := newInput(&fakeKubernetesClient{get: func(ctx context.Context, key ctrlclient.ObjectKey, obj ctrlclient.Object) error { + mc := obj.(*mcapi.ModuleConfig) + *mc = *NewModuleConfigForTest(map[string]any{}) + return nil + }}, nil) - if HasModuleConfig(newInput(values)) { + ok, err := HasModuleConfig(context.Background(), input) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if ok { t.Fatalf("expected HasModuleConfig to return false") } }) - t.Run("returns true when moduleConfig is a non-empty object", func(t *testing.T) { - values := mock.NewPatchableValuesCollectorMock(t) - values.GetMock.When(InternalValuesConfigCopyPath).Then(gjson.Parse(`{"dvcr":{},"virtualMachineCIDRs":["10.0.0.0/24"]}`)) - - if !HasModuleConfig(newInput(values)) { + t.Run("returns true when required settings exist", func(t *testing.T) { + input := newInput(&fakeKubernetesClient{get: func(ctx context.Context, key ctrlclient.ObjectKey, obj ctrlclient.Object) error { + mc := obj.(*mcapi.ModuleConfig) + *mc = *NewModuleConfigForTest(map[string]any{ + "virtualMachineCIDRs": []any{"10.0.0.0/24"}, + "dvcr": map[string]any{}, + }) + return nil + }}, nil) + + ok, err := HasModuleConfig(context.Background(), input) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !ok { t.Fatalf("expected HasModuleConfig to return true") } }) + + t.Run("returns error when kubernetes client cannot be created", func(t *testing.T) { + input := newInput(nil, staticErr("boom")) + + ok, err := HasModuleConfig(context.Background(), input) + if err == nil { + t.Fatalf("expected error") + } + if ok { + t.Fatalf("expected HasModuleConfig to return false") + } + }) } + +type staticErr string + +func (e staticErr) Error() string { return string(e) } From d438557ecb02c1a509384fd198b442aae93baac7 Mon Sep 17 00:00:00 2001 From: Dmitry Lopatin Date: Tue, 21 Apr 2026 13:54:30 +0300 Subject: [PATCH 3/7] after review Signed-off-by: Dmitry Lopatin --- .../hook_test.go | 12 +++++++++++- .../pkg/hooks/discovery-workload-nodes/hook_test.go | 3 ++- .../pkg/hooks/generate-secret-for-dvcr/hook_test.go | 11 ++++++++++- .../hooks/tls-certificates-api-proxy/main_test.go | 8 ++++++++ .../pkg/hooks/tls-certificates-api/main_test.go | 8 ++++++++ .../hooks/tls-certificates-controller/hook_test.go | 8 ++++++++ .../pkg/hooks/tls-certificates-dvcr/hook_test.go | 13 +++++++++++++ images/hooks/pkg/settings/module_config.go | 12 +++++++++++- 8 files changed, 71 insertions(+), 4 deletions(-) diff --git a/images/hooks/pkg/hooks/discovery-clusterip-service-for-dvcr/hook_test.go b/images/hooks/pkg/hooks/discovery-clusterip-service-for-dvcr/hook_test.go index 3d1a2cb02d..2d3836a9db 100644 --- a/images/hooks/pkg/hooks/discovery-clusterip-service-for-dvcr/hook_test.go +++ b/images/hooks/pkg/hooks/discovery-clusterip-service-for-dvcr/hook_test.go @@ -25,11 +25,12 @@ import ( "github.com/tidwall/gjson" ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" + "hooks/pkg/settings" + "github.com/deckhouse/deckhouse/pkg/log" "github.com/deckhouse/module-sdk/pkg" "github.com/deckhouse/module-sdk/testing/mock" mcapi "github.com/deckhouse/virtualization-controller/pkg/controller/moduleconfig/api" - "github.com/deckhouse/virtualization/hooks/pkg/settings" ) func TestDiscoveryClusterIPServiceForDVCR(t *testing.T) { @@ -98,3 +99,12 @@ var _ = Describe("DiscoveryClusterIPServiceForDVCR", func() { Expect(handleDiscoveryService(context.Background(), newInput())).To(Succeed()) }) }) + +type fakeKubernetesClient struct { + pkg.KubernetesClient + get func(ctx context.Context, key ctrlclient.ObjectKey, obj ctrlclient.Object) error +} + +func (f *fakeKubernetesClient) Get(ctx context.Context, key ctrlclient.ObjectKey, obj ctrlclient.Object, _ ...ctrlclient.GetOption) error { + return f.get(ctx, key, obj) +} diff --git a/images/hooks/pkg/hooks/discovery-workload-nodes/hook_test.go b/images/hooks/pkg/hooks/discovery-workload-nodes/hook_test.go index 91ede8638e..7d0b6e5774 100644 --- a/images/hooks/pkg/hooks/discovery-workload-nodes/hook_test.go +++ b/images/hooks/pkg/hooks/discovery-workload-nodes/hook_test.go @@ -24,11 +24,12 @@ import ( . "github.com/onsi/gomega" ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" + "hooks/pkg/settings" + "github.com/deckhouse/deckhouse/pkg/log" "github.com/deckhouse/module-sdk/pkg" "github.com/deckhouse/module-sdk/testing/mock" mcapi "github.com/deckhouse/virtualization-controller/pkg/controller/moduleconfig/api" - "github.com/deckhouse/virtualization/hooks/pkg/settings" ) func TestDiscoveryWorkloadNodes(t *testing.T) { diff --git a/images/hooks/pkg/hooks/generate-secret-for-dvcr/hook_test.go b/images/hooks/pkg/hooks/generate-secret-for-dvcr/hook_test.go index 2874c38414..f030afa20b 100644 --- a/images/hooks/pkg/hooks/generate-secret-for-dvcr/hook_test.go +++ b/images/hooks/pkg/hooks/generate-secret-for-dvcr/hook_test.go @@ -30,7 +30,7 @@ import ( "github.com/deckhouse/module-sdk/pkg" "github.com/deckhouse/module-sdk/testing/mock" mcapi "github.com/deckhouse/virtualization-controller/pkg/controller/moduleconfig/api" - "github.com/deckhouse/virtualization/hooks/pkg/settings" + "hooks/pkg/settings" ) func TestSetDVCRSecrets(t *testing.T) { @@ -235,3 +235,12 @@ var _ = Describe("Generate secrets", func() { Expect(validateHtpasswd(password, htpasswd)).To(BeTrue()) }) }) + +type fakeKubernetesClient struct { + pkg.KubernetesClient + get func(ctx context.Context, key ctrlclient.ObjectKey, obj ctrlclient.Object) error +} + +func (f *fakeKubernetesClient) Get(ctx context.Context, key ctrlclient.ObjectKey, obj ctrlclient.Object, _ ...ctrlclient.GetOption) error { + return f.get(ctx, key, obj) +} diff --git a/images/hooks/pkg/hooks/tls-certificates-api-proxy/main_test.go b/images/hooks/pkg/hooks/tls-certificates-api-proxy/main_test.go index 6318568aed..96910fab64 100644 --- a/images/hooks/pkg/hooks/tls-certificates-api-proxy/main_test.go +++ b/images/hooks/pkg/hooks/tls-certificates-api-proxy/main_test.go @@ -20,10 +20,18 @@ import ( "context" "testing" +<<<<<<< HEAD "github.com/deckhouse/module-sdk/pkg" "github.com/deckhouse/module-sdk/testing/mock" mcapi "github.com/deckhouse/virtualization-controller/pkg/controller/moduleconfig/api" "github.com/deckhouse/virtualization/hooks/pkg/settings" +======= + "hooks/pkg/settings" + + "github.com/deckhouse/module-sdk/pkg" + "github.com/deckhouse/module-sdk/testing/mock" + mcapi "github.com/deckhouse/virtualization-controller/pkg/controller/moduleconfig/api" +>>>>>>> e2b60b40 (after review) ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" ) diff --git a/images/hooks/pkg/hooks/tls-certificates-api/main_test.go b/images/hooks/pkg/hooks/tls-certificates-api/main_test.go index a8392f6c5d..1afe3c2bfd 100644 --- a/images/hooks/pkg/hooks/tls-certificates-api/main_test.go +++ b/images/hooks/pkg/hooks/tls-certificates-api/main_test.go @@ -20,10 +20,18 @@ import ( "context" "testing" +<<<<<<< HEAD "github.com/deckhouse/module-sdk/pkg" "github.com/deckhouse/module-sdk/testing/mock" mcapi "github.com/deckhouse/virtualization-controller/pkg/controller/moduleconfig/api" "github.com/deckhouse/virtualization/hooks/pkg/settings" +======= + "hooks/pkg/settings" + + "github.com/deckhouse/module-sdk/pkg" + "github.com/deckhouse/module-sdk/testing/mock" + mcapi "github.com/deckhouse/virtualization-controller/pkg/controller/moduleconfig/api" +>>>>>>> e2b60b40 (after review) ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" ) diff --git a/images/hooks/pkg/hooks/tls-certificates-controller/hook_test.go b/images/hooks/pkg/hooks/tls-certificates-controller/hook_test.go index 6153f135e6..c2674be5ea 100644 --- a/images/hooks/pkg/hooks/tls-certificates-controller/hook_test.go +++ b/images/hooks/pkg/hooks/tls-certificates-controller/hook_test.go @@ -20,10 +20,18 @@ import ( "context" "testing" +<<<<<<< HEAD "github.com/deckhouse/module-sdk/pkg" "github.com/deckhouse/module-sdk/testing/mock" mcapi "github.com/deckhouse/virtualization-controller/pkg/controller/moduleconfig/api" "github.com/deckhouse/virtualization/hooks/pkg/settings" +======= + "hooks/pkg/settings" + + "github.com/deckhouse/module-sdk/pkg" + "github.com/deckhouse/module-sdk/testing/mock" + mcapi "github.com/deckhouse/virtualization-controller/pkg/controller/moduleconfig/api" +>>>>>>> e2b60b40 (after review) ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" ) diff --git a/images/hooks/pkg/hooks/tls-certificates-dvcr/hook_test.go b/images/hooks/pkg/hooks/tls-certificates-dvcr/hook_test.go index 43dd9a96ae..d840066204 100644 --- a/images/hooks/pkg/hooks/tls-certificates-dvcr/hook_test.go +++ b/images/hooks/pkg/hooks/tls-certificates-dvcr/hook_test.go @@ -20,10 +20,18 @@ import ( "context" "testing" +<<<<<<< HEAD "github.com/deckhouse/module-sdk/pkg" "github.com/deckhouse/module-sdk/testing/mock" mcapi "github.com/deckhouse/virtualization-controller/pkg/controller/moduleconfig/api" "github.com/deckhouse/virtualization/hooks/pkg/settings" +======= + "hooks/pkg/settings" + + "github.com/deckhouse/module-sdk/pkg" + "github.com/deckhouse/module-sdk/testing/mock" + mcapi "github.com/deckhouse/virtualization-controller/pkg/controller/moduleconfig/api" +>>>>>>> e2b60b40 (after review) ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -40,7 +48,12 @@ func TestBeforeHookCheckSkipsWithoutModuleConfig(t *testing.T) { dc := mock.NewDependencyContainerMock(t) dc.GetK8sClientMock.Return(&fakeKubernetesClient{get: func(ctx context.Context, key ctrlclient.ObjectKey, obj ctrlclient.Object) error { mc := obj.(*mcapi.ModuleConfig) +<<<<<<< HEAD *mc = *settings.NewModuleConfigForTest(nil) +======= + mc.Name = "virtualization" + mc.Spec.Settings = nil +>>>>>>> e2b60b40 (after review) return nil }}, nil) diff --git a/images/hooks/pkg/settings/module_config.go b/images/hooks/pkg/settings/module_config.go index 6b79dfc5f9..75616184c8 100644 --- a/images/hooks/pkg/settings/module_config.go +++ b/images/hooks/pkg/settings/module_config.go @@ -32,7 +32,7 @@ func HasModuleConfig(ctx context.Context, input *pkg.HookInput) (bool, error) { return false, fmt.Errorf("dependency container is nil") } - k8sClient, err := input.DC.GetK8sClient() + k8sClient, err := input.DC.GetK8sClient(addModuleConfigScheme()) if err != nil { return false, fmt.Errorf("get kubernetes client: %w", err) } @@ -61,6 +61,16 @@ func HasModuleConfig(ctx context.Context, input *pkg.HookInput) (bool, error) { return true, nil } +type moduleConfigSchemeOption struct{} + +func (moduleConfigSchemeOption) Apply(optsApplier pkg.KubernetesOptionApplier) { + optsApplier.WithSchemeBuilder(mcapi.SchemeBuilder) +} + +func addModuleConfigScheme() pkg.KubernetesOption { + return moduleConfigSchemeOption{} +} + func NewModuleConfigForTest(settings map[string]any) *mcapi.ModuleConfig { return &mcapi.ModuleConfig{ TypeMeta: metav1.TypeMeta{ From 6141369aebea3ae6f3d19af98ccce8a8c97ad1e8 Mon Sep 17 00:00:00 2001 From: Dmitry Lopatin Date: Tue, 21 Apr 2026 16:48:32 +0300 Subject: [PATCH 4/7] fix(module): add module config scheme for hook client Signed-off-by: Dmitry Lopatin --- .../hook_test.go | 3 +- .../test_helpers_test.go | 33 ------------------- .../discovery-workload-nodes/hook_test.go | 3 +- .../generate-secret-for-dvcr/hook_test.go | 2 +- .../test_helpers_test.go | 33 ------------------- .../tls-certificates-api-proxy/main_test.go | 11 ++----- .../hooks/tls-certificates-api/main_test.go | 11 ++----- .../tls-certificates-controller/hook_test.go | 11 ++----- .../hooks/tls-certificates-dvcr/hook_test.go | 15 ++------- images/hooks/pkg/settings/module_config.go | 5 +-- .../hooks/pkg/settings/module_config_test.go | 13 ++++---- 11 files changed, 21 insertions(+), 119 deletions(-) delete mode 100644 images/hooks/pkg/hooks/discovery-clusterip-service-for-dvcr/test_helpers_test.go delete mode 100644 images/hooks/pkg/hooks/generate-secret-for-dvcr/test_helpers_test.go diff --git a/images/hooks/pkg/hooks/discovery-clusterip-service-for-dvcr/hook_test.go b/images/hooks/pkg/hooks/discovery-clusterip-service-for-dvcr/hook_test.go index 2d3836a9db..4291b28184 100644 --- a/images/hooks/pkg/hooks/discovery-clusterip-service-for-dvcr/hook_test.go +++ b/images/hooks/pkg/hooks/discovery-clusterip-service-for-dvcr/hook_test.go @@ -25,12 +25,11 @@ import ( "github.com/tidwall/gjson" ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" - "hooks/pkg/settings" - "github.com/deckhouse/deckhouse/pkg/log" "github.com/deckhouse/module-sdk/pkg" "github.com/deckhouse/module-sdk/testing/mock" mcapi "github.com/deckhouse/virtualization-controller/pkg/controller/moduleconfig/api" + "github.com/deckhouse/virtualization/hooks/pkg/settings" ) func TestDiscoveryClusterIPServiceForDVCR(t *testing.T) { diff --git a/images/hooks/pkg/hooks/discovery-clusterip-service-for-dvcr/test_helpers_test.go b/images/hooks/pkg/hooks/discovery-clusterip-service-for-dvcr/test_helpers_test.go deleted file mode 100644 index d7472e67a8..0000000000 --- a/images/hooks/pkg/hooks/discovery-clusterip-service-for-dvcr/test_helpers_test.go +++ /dev/null @@ -1,33 +0,0 @@ -/* -Copyright 2026 Flant JSC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package discovery_clusterip_service_for_dvcr - -import ( - "context" - - "github.com/deckhouse/module-sdk/pkg" - ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" -) - -type fakeKubernetesClient struct { - pkg.KubernetesClient - get func(ctx context.Context, key ctrlclient.ObjectKey, obj ctrlclient.Object) error -} - -func (f *fakeKubernetesClient) Get(ctx context.Context, key ctrlclient.ObjectKey, obj ctrlclient.Object, _ ...ctrlclient.GetOption) error { - return f.get(ctx, key, obj) -} diff --git a/images/hooks/pkg/hooks/discovery-workload-nodes/hook_test.go b/images/hooks/pkg/hooks/discovery-workload-nodes/hook_test.go index 7d0b6e5774..91ede8638e 100644 --- a/images/hooks/pkg/hooks/discovery-workload-nodes/hook_test.go +++ b/images/hooks/pkg/hooks/discovery-workload-nodes/hook_test.go @@ -24,12 +24,11 @@ import ( . "github.com/onsi/gomega" ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" - "hooks/pkg/settings" - "github.com/deckhouse/deckhouse/pkg/log" "github.com/deckhouse/module-sdk/pkg" "github.com/deckhouse/module-sdk/testing/mock" mcapi "github.com/deckhouse/virtualization-controller/pkg/controller/moduleconfig/api" + "github.com/deckhouse/virtualization/hooks/pkg/settings" ) func TestDiscoveryWorkloadNodes(t *testing.T) { diff --git a/images/hooks/pkg/hooks/generate-secret-for-dvcr/hook_test.go b/images/hooks/pkg/hooks/generate-secret-for-dvcr/hook_test.go index f030afa20b..54b199c24c 100644 --- a/images/hooks/pkg/hooks/generate-secret-for-dvcr/hook_test.go +++ b/images/hooks/pkg/hooks/generate-secret-for-dvcr/hook_test.go @@ -30,7 +30,7 @@ import ( "github.com/deckhouse/module-sdk/pkg" "github.com/deckhouse/module-sdk/testing/mock" mcapi "github.com/deckhouse/virtualization-controller/pkg/controller/moduleconfig/api" - "hooks/pkg/settings" + "github.com/deckhouse/virtualization/hooks/pkg/settings" ) func TestSetDVCRSecrets(t *testing.T) { diff --git a/images/hooks/pkg/hooks/generate-secret-for-dvcr/test_helpers_test.go b/images/hooks/pkg/hooks/generate-secret-for-dvcr/test_helpers_test.go deleted file mode 100644 index 8838fc8edb..0000000000 --- a/images/hooks/pkg/hooks/generate-secret-for-dvcr/test_helpers_test.go +++ /dev/null @@ -1,33 +0,0 @@ -/* -Copyright 2026 Flant JSC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package generate_secret_for_dvcr - -import ( - "context" - - "github.com/deckhouse/module-sdk/pkg" - ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" -) - -type fakeKubernetesClient struct { - pkg.KubernetesClient - get func(ctx context.Context, key ctrlclient.ObjectKey, obj ctrlclient.Object) error -} - -func (f *fakeKubernetesClient) Get(ctx context.Context, key ctrlclient.ObjectKey, obj ctrlclient.Object, _ ...ctrlclient.GetOption) error { - return f.get(ctx, key, obj) -} diff --git a/images/hooks/pkg/hooks/tls-certificates-api-proxy/main_test.go b/images/hooks/pkg/hooks/tls-certificates-api-proxy/main_test.go index 96910fab64..4f2979e318 100644 --- a/images/hooks/pkg/hooks/tls-certificates-api-proxy/main_test.go +++ b/images/hooks/pkg/hooks/tls-certificates-api-proxy/main_test.go @@ -20,19 +20,12 @@ import ( "context" "testing" -<<<<<<< HEAD - "github.com/deckhouse/module-sdk/pkg" - "github.com/deckhouse/module-sdk/testing/mock" - mcapi "github.com/deckhouse/virtualization-controller/pkg/controller/moduleconfig/api" - "github.com/deckhouse/virtualization/hooks/pkg/settings" -======= - "hooks/pkg/settings" + ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" "github.com/deckhouse/module-sdk/pkg" "github.com/deckhouse/module-sdk/testing/mock" mcapi "github.com/deckhouse/virtualization-controller/pkg/controller/moduleconfig/api" ->>>>>>> e2b60b40 (after review) - ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" + "github.com/deckhouse/virtualization/hooks/pkg/settings" ) type fakeKubernetesClient struct { diff --git a/images/hooks/pkg/hooks/tls-certificates-api/main_test.go b/images/hooks/pkg/hooks/tls-certificates-api/main_test.go index 1afe3c2bfd..43e7cdccc8 100644 --- a/images/hooks/pkg/hooks/tls-certificates-api/main_test.go +++ b/images/hooks/pkg/hooks/tls-certificates-api/main_test.go @@ -20,19 +20,12 @@ import ( "context" "testing" -<<<<<<< HEAD - "github.com/deckhouse/module-sdk/pkg" - "github.com/deckhouse/module-sdk/testing/mock" - mcapi "github.com/deckhouse/virtualization-controller/pkg/controller/moduleconfig/api" - "github.com/deckhouse/virtualization/hooks/pkg/settings" -======= - "hooks/pkg/settings" + ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" "github.com/deckhouse/module-sdk/pkg" "github.com/deckhouse/module-sdk/testing/mock" mcapi "github.com/deckhouse/virtualization-controller/pkg/controller/moduleconfig/api" ->>>>>>> e2b60b40 (after review) - ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" + "github.com/deckhouse/virtualization/hooks/pkg/settings" ) type fakeKubernetesClient struct { diff --git a/images/hooks/pkg/hooks/tls-certificates-controller/hook_test.go b/images/hooks/pkg/hooks/tls-certificates-controller/hook_test.go index c2674be5ea..541ab85b8d 100644 --- a/images/hooks/pkg/hooks/tls-certificates-controller/hook_test.go +++ b/images/hooks/pkg/hooks/tls-certificates-controller/hook_test.go @@ -20,19 +20,12 @@ import ( "context" "testing" -<<<<<<< HEAD - "github.com/deckhouse/module-sdk/pkg" - "github.com/deckhouse/module-sdk/testing/mock" - mcapi "github.com/deckhouse/virtualization-controller/pkg/controller/moduleconfig/api" - "github.com/deckhouse/virtualization/hooks/pkg/settings" -======= - "hooks/pkg/settings" + ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" "github.com/deckhouse/module-sdk/pkg" "github.com/deckhouse/module-sdk/testing/mock" mcapi "github.com/deckhouse/virtualization-controller/pkg/controller/moduleconfig/api" ->>>>>>> e2b60b40 (after review) - ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" + "github.com/deckhouse/virtualization/hooks/pkg/settings" ) type fakeKubernetesClient struct { diff --git a/images/hooks/pkg/hooks/tls-certificates-dvcr/hook_test.go b/images/hooks/pkg/hooks/tls-certificates-dvcr/hook_test.go index d840066204..d483d5dbc8 100644 --- a/images/hooks/pkg/hooks/tls-certificates-dvcr/hook_test.go +++ b/images/hooks/pkg/hooks/tls-certificates-dvcr/hook_test.go @@ -20,19 +20,12 @@ import ( "context" "testing" -<<<<<<< HEAD - "github.com/deckhouse/module-sdk/pkg" - "github.com/deckhouse/module-sdk/testing/mock" - mcapi "github.com/deckhouse/virtualization-controller/pkg/controller/moduleconfig/api" - "github.com/deckhouse/virtualization/hooks/pkg/settings" -======= - "hooks/pkg/settings" + ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" "github.com/deckhouse/module-sdk/pkg" "github.com/deckhouse/module-sdk/testing/mock" mcapi "github.com/deckhouse/virtualization-controller/pkg/controller/moduleconfig/api" ->>>>>>> e2b60b40 (after review) - ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" + "github.com/deckhouse/virtualization/hooks/pkg/settings" ) type fakeKubernetesClient struct { @@ -48,12 +41,8 @@ func TestBeforeHookCheckSkipsWithoutModuleConfig(t *testing.T) { dc := mock.NewDependencyContainerMock(t) dc.GetK8sClientMock.Return(&fakeKubernetesClient{get: func(ctx context.Context, key ctrlclient.ObjectKey, obj ctrlclient.Object) error { mc := obj.(*mcapi.ModuleConfig) -<<<<<<< HEAD - *mc = *settings.NewModuleConfigForTest(nil) -======= mc.Name = "virtualization" mc.Spec.Settings = nil ->>>>>>> e2b60b40 (after review) return nil }}, nil) diff --git a/images/hooks/pkg/settings/module_config.go b/images/hooks/pkg/settings/module_config.go index 75616184c8..6129dd1b87 100644 --- a/images/hooks/pkg/settings/module_config.go +++ b/images/hooks/pkg/settings/module_config.go @@ -20,11 +20,12 @@ import ( "context" "fmt" - "github.com/deckhouse/module-sdk/pkg" - mcapi "github.com/deckhouse/virtualization-controller/pkg/controller/moduleconfig/api" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/deckhouse/module-sdk/pkg" + mcapi "github.com/deckhouse/virtualization-controller/pkg/controller/moduleconfig/api" ) func HasModuleConfig(ctx context.Context, input *pkg.HookInput) (bool, error) { diff --git a/images/hooks/pkg/settings/module_config_test.go b/images/hooks/pkg/settings/module_config_test.go index 4a69ef3b1b..6d60118e8a 100644 --- a/images/hooks/pkg/settings/module_config_test.go +++ b/images/hooks/pkg/settings/module_config_test.go @@ -20,12 +20,13 @@ import ( "context" "testing" - "github.com/deckhouse/module-sdk/pkg" - "github.com/deckhouse/module-sdk/testing/mock" - mcapi "github.com/deckhouse/virtualization-controller/pkg/controller/moduleconfig/api" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime/schema" ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/deckhouse/module-sdk/pkg" + "github.com/deckhouse/module-sdk/testing/mock" + mcapi "github.com/deckhouse/virtualization-controller/pkg/controller/moduleconfig/api" ) type fakeKubernetesClient struct { @@ -110,7 +111,7 @@ func TestHasModuleConfig(t *testing.T) { }) t.Run("returns error when kubernetes client cannot be created", func(t *testing.T) { - input := newInput(nil, staticErr("boom")) + input := newInput(nil, staticError("boom")) ok, err := HasModuleConfig(context.Background(), input) if err == nil { @@ -122,6 +123,6 @@ func TestHasModuleConfig(t *testing.T) { }) } -type staticErr string +type staticError string -func (e staticErr) Error() string { return string(e) } +func (e staticError) Error() string { return string(e) } From ee3b81459b25e18f718b2ea8bb7ade80ace66efd Mon Sep 17 00:00:00 2001 From: Dmitry Lopatin Date: Wed, 22 Apr 2026 12:09:50 +0300 Subject: [PATCH 5/7] fix after review Signed-off-by: Dmitry Lopatin --- .../hooks/tls-certificates-api-proxy/main.go | 21 +++++++------------ .../tls-certificates-api-proxy/main_test.go | 11 ++++++---- .../pkg/hooks/tls-certificates-api/main.go | 21 +++++++------------ .../hooks/tls-certificates-api/main_test.go | 11 ++++++---- .../hooks/tls-certificates-controller/hook.go | 21 +++++++------------ .../tls-certificates-controller/hook_test.go | 11 ++++++---- 6 files changed, 42 insertions(+), 54 deletions(-) diff --git a/images/hooks/pkg/hooks/tls-certificates-api-proxy/main.go b/images/hooks/pkg/hooks/tls-certificates-api-proxy/main.go index fa98fc912d..f444398ada 100644 --- a/images/hooks/pkg/hooks/tls-certificates-api-proxy/main.go +++ b/images/hooks/pkg/hooks/tls-certificates-api-proxy/main.go @@ -24,7 +24,6 @@ import ( tlscertificate "github.com/deckhouse/module-sdk/common-hooks/tls-certificate" "github.com/deckhouse/module-sdk/pkg" - "github.com/deckhouse/module-sdk/pkg/registry" "github.com/deckhouse/virtualization/hooks/pkg/settings" ) @@ -36,20 +35,14 @@ var conf = tlscertificate.GenSelfSignedTLSHookConf{ FullValuesPathPrefix: fmt.Sprintf("%s.internal.apiserver.proxyCert", settings.ModuleName), CommonCAValuesPath: fmt.Sprintf("%s.internal.rootCA", settings.ModuleName), Usages: []v1.KeyUsage{v1.UsageClientAuth}, -} - -var reconcile = func(conf tlscertificate.GenSelfSignedTLSHookConf) pkg.ReconcileFunc { - return func(ctx context.Context, input *pkg.HookInput) error { - hasModuleConfig, err := settings.HasModuleConfig(ctx, input) + BeforeHookCheck: func(input *pkg.HookInput) bool { + hasModuleConfig, err := settings.HasModuleConfig(context.Background(), input) if err != nil { - return err + input.Logger.Error("Check module config before API proxy TLS hook", "error", err) + return false } - if !hasModuleConfig { - return nil - } - - return tlscertificate.GenSelfSignedTLS(conf)(ctx, input) - } + return hasModuleConfig + }, } -var _ = registry.RegisterFunc(tlscertificate.GenSelfSignedTLSConfig(conf), reconcile(conf)) +var _ = tlscertificate.RegisterInternalTLSHookEM(conf) diff --git a/images/hooks/pkg/hooks/tls-certificates-api-proxy/main_test.go b/images/hooks/pkg/hooks/tls-certificates-api-proxy/main_test.go index 4f2979e318..c275916659 100644 --- a/images/hooks/pkg/hooks/tls-certificates-api-proxy/main_test.go +++ b/images/hooks/pkg/hooks/tls-certificates-api-proxy/main_test.go @@ -37,7 +37,7 @@ func (f *fakeKubernetesClient) Get(ctx context.Context, key ctrlclient.ObjectKey return f.get(ctx, key, obj) } -func TestReconcileSkipsWithoutModuleConfig(t *testing.T) { +func TestBeforeHookCheckSkipsWithoutModuleConfig(t *testing.T) { dc := mock.NewDependencyContainerMock(t) dc.GetK8sClientMock.Return(&fakeKubernetesClient{get: func(ctx context.Context, key ctrlclient.ObjectKey, obj ctrlclient.Object) error { mc := obj.(*mcapi.ModuleConfig) @@ -45,8 +45,11 @@ func TestReconcileSkipsWithoutModuleConfig(t *testing.T) { return nil }}, nil) - input := &pkg.HookInput{DC: dc} - if err := reconcile(conf)(context.Background(), input); err != nil { - t.Fatalf("expected nil error, got %v", err) + if conf.BeforeHookCheck == nil { + t.Fatal("expected BeforeHookCheck to be configured") + } + + if ok := conf.BeforeHookCheck(&pkg.HookInput{DC: dc}); ok { + t.Fatalf("expected BeforeHookCheck to return false") } } diff --git a/images/hooks/pkg/hooks/tls-certificates-api/main.go b/images/hooks/pkg/hooks/tls-certificates-api/main.go index cb83d857c6..95eecc1aa6 100644 --- a/images/hooks/pkg/hooks/tls-certificates-api/main.go +++ b/images/hooks/pkg/hooks/tls-certificates-api/main.go @@ -22,7 +22,6 @@ import ( tlscertificate "github.com/deckhouse/module-sdk/common-hooks/tls-certificate" "github.com/deckhouse/module-sdk/pkg" - "github.com/deckhouse/module-sdk/pkg/registry" "github.com/deckhouse/virtualization/hooks/pkg/settings" ) @@ -43,20 +42,14 @@ var conf = tlscertificate.GenSelfSignedTLSHookConf{ FullValuesPathPrefix: fmt.Sprintf("%s.internal.apiserver.cert", settings.ModuleName), CommonCAValuesPath: fmt.Sprintf("%s.internal.rootCA", settings.ModuleName), -} - -var reconcile = func(conf tlscertificate.GenSelfSignedTLSHookConf) pkg.ReconcileFunc { - return func(ctx context.Context, input *pkg.HookInput) error { - hasModuleConfig, err := settings.HasModuleConfig(ctx, input) + BeforeHookCheck: func(input *pkg.HookInput) bool { + hasModuleConfig, err := settings.HasModuleConfig(context.Background(), input) if err != nil { - return err + input.Logger.Error("Check module config before API TLS hook", "error", err) + return false } - if !hasModuleConfig { - return nil - } - - return tlscertificate.GenSelfSignedTLS(conf)(ctx, input) - } + return hasModuleConfig + }, } -var _ = registry.RegisterFunc(tlscertificate.GenSelfSignedTLSConfig(conf), reconcile(conf)) +var _ = tlscertificate.RegisterInternalTLSHookEM(conf) diff --git a/images/hooks/pkg/hooks/tls-certificates-api/main_test.go b/images/hooks/pkg/hooks/tls-certificates-api/main_test.go index 43e7cdccc8..c53f58aa92 100644 --- a/images/hooks/pkg/hooks/tls-certificates-api/main_test.go +++ b/images/hooks/pkg/hooks/tls-certificates-api/main_test.go @@ -37,7 +37,7 @@ func (f *fakeKubernetesClient) Get(ctx context.Context, key ctrlclient.ObjectKey return f.get(ctx, key, obj) } -func TestReconcileSkipsWithoutModuleConfig(t *testing.T) { +func TestBeforeHookCheckSkipsWithoutModuleConfig(t *testing.T) { dc := mock.NewDependencyContainerMock(t) dc.GetK8sClientMock.Return(&fakeKubernetesClient{get: func(ctx context.Context, key ctrlclient.ObjectKey, obj ctrlclient.Object) error { mc := obj.(*mcapi.ModuleConfig) @@ -45,8 +45,11 @@ func TestReconcileSkipsWithoutModuleConfig(t *testing.T) { return nil }}, nil) - input := &pkg.HookInput{DC: dc} - if err := reconcile(conf)(context.Background(), input); err != nil { - t.Fatalf("expected nil error, got %v", err) + if conf.BeforeHookCheck == nil { + t.Fatal("expected BeforeHookCheck to be configured") + } + + if ok := conf.BeforeHookCheck(&pkg.HookInput{DC: dc}); ok { + t.Fatalf("expected BeforeHookCheck to return false") } } diff --git a/images/hooks/pkg/hooks/tls-certificates-controller/hook.go b/images/hooks/pkg/hooks/tls-certificates-controller/hook.go index 50fe56b3f5..d92f278b58 100644 --- a/images/hooks/pkg/hooks/tls-certificates-controller/hook.go +++ b/images/hooks/pkg/hooks/tls-certificates-controller/hook.go @@ -22,7 +22,6 @@ import ( tlscertificate "github.com/deckhouse/module-sdk/common-hooks/tls-certificate" "github.com/deckhouse/module-sdk/pkg" - "github.com/deckhouse/module-sdk/pkg/registry" "github.com/deckhouse/virtualization/hooks/pkg/settings" ) @@ -43,20 +42,14 @@ var conf = tlscertificate.GenSelfSignedTLSHookConf{ FullValuesPathPrefix: fmt.Sprintf("%s.internal.controller.cert", settings.ModuleName), CommonCAValuesPath: fmt.Sprintf("%s.internal.rootCA", settings.ModuleName), -} - -var reconcile = func(conf tlscertificate.GenSelfSignedTLSHookConf) pkg.ReconcileFunc { - return func(ctx context.Context, input *pkg.HookInput) error { - hasModuleConfig, err := settings.HasModuleConfig(ctx, input) + BeforeHookCheck: func(input *pkg.HookInput) bool { + hasModuleConfig, err := settings.HasModuleConfig(context.Background(), input) if err != nil { - return err + input.Logger.Error("Check module config before controller TLS hook", "error", err) + return false } - if !hasModuleConfig { - return nil - } - - return tlscertificate.GenSelfSignedTLS(conf)(ctx, input) - } + return hasModuleConfig + }, } -var _ = registry.RegisterFunc(tlscertificate.GenSelfSignedTLSConfig(conf), reconcile(conf)) +var _ = tlscertificate.RegisterInternalTLSHookEM(conf) diff --git a/images/hooks/pkg/hooks/tls-certificates-controller/hook_test.go b/images/hooks/pkg/hooks/tls-certificates-controller/hook_test.go index 541ab85b8d..93905c3ead 100644 --- a/images/hooks/pkg/hooks/tls-certificates-controller/hook_test.go +++ b/images/hooks/pkg/hooks/tls-certificates-controller/hook_test.go @@ -37,7 +37,7 @@ func (f *fakeKubernetesClient) Get(ctx context.Context, key ctrlclient.ObjectKey return f.get(ctx, key, obj) } -func TestReconcileSkipsWithoutModuleConfig(t *testing.T) { +func TestBeforeHookCheckSkipsWithoutModuleConfig(t *testing.T) { dc := mock.NewDependencyContainerMock(t) dc.GetK8sClientMock.Return(&fakeKubernetesClient{get: func(ctx context.Context, key ctrlclient.ObjectKey, obj ctrlclient.Object) error { mc := obj.(*mcapi.ModuleConfig) @@ -45,8 +45,11 @@ func TestReconcileSkipsWithoutModuleConfig(t *testing.T) { return nil }}, nil) - input := &pkg.HookInput{DC: dc} - if err := reconcile(conf)(context.Background(), input); err != nil { - t.Fatalf("expected nil error, got %v", err) + if conf.BeforeHookCheck == nil { + t.Fatal("expected BeforeHookCheck to be configured") + } + + if ok := conf.BeforeHookCheck(&pkg.HookInput{DC: dc}); ok { + t.Fatalf("expected BeforeHookCheck to return false") } } From 698e0d3df3dcc7765f76dde48b213f60ef7dc8c8 Mon Sep 17 00:00:00 2001 From: Dmitry Lopatin Date: Wed, 22 Apr 2026 13:30:37 +0300 Subject: [PATCH 6/7] fix after review Signed-off-by: Dmitry Lopatin --- .../hook.go | 4 +- .../hooks/discovery-workload-nodes/hook.go | 4 +- .../hooks/generate-secret-for-dvcr/hook.go | 4 +- .../hooks/tls-certificates-api-proxy/main.go | 4 +- .../pkg/hooks/tls-certificates-api/main.go | 4 +- .../pkg/hooks/tls-certificates-audit/hook.go | 4 +- .../hooks/tls-certificates-controller/hook.go | 4 +- .../pkg/hooks/tls-certificates-dvcr/hook.go | 4 +- .../hooks/tls-certificates-dvcr/hook_test.go | 2 +- images/hooks/pkg/settings/module_config.go | 6 ++- .../hooks/pkg/settings/module_config_test.go | 46 ++++++++++++++----- 11 files changed, 57 insertions(+), 29 deletions(-) diff --git a/images/hooks/pkg/hooks/discovery-clusterip-service-for-dvcr/hook.go b/images/hooks/pkg/hooks/discovery-clusterip-service-for-dvcr/hook.go index 91aa66f0f4..31acacbe59 100644 --- a/images/hooks/pkg/hooks/discovery-clusterip-service-for-dvcr/hook.go +++ b/images/hooks/pkg/hooks/discovery-clusterip-service-for-dvcr/hook.go @@ -65,11 +65,11 @@ var configDiscoveryService = &pkg.HookConfig{ } func handleDiscoveryService(ctx context.Context, input *pkg.HookInput) error { - hasModuleConfig, err := settings.HasModuleConfig(ctx, input) + canRun, err := settings.CanRunWithModuleConfig(ctx, input) if err != nil { return err } - if !hasModuleConfig { + if !canRun { return nil } diff --git a/images/hooks/pkg/hooks/discovery-workload-nodes/hook.go b/images/hooks/pkg/hooks/discovery-workload-nodes/hook.go index 775819914b..798fb84dc1 100644 --- a/images/hooks/pkg/hooks/discovery-workload-nodes/hook.go +++ b/images/hooks/pkg/hooks/discovery-workload-nodes/hook.go @@ -79,11 +79,11 @@ var configDiscoveryService = &pkg.HookConfig{ } func handleDiscoveryNodes(ctx context.Context, input *pkg.HookInput) error { - hasModuleConfig, err := settings.HasModuleConfig(ctx, input) + canRun, err := settings.CanRunWithModuleConfig(ctx, input) if err != nil { return err } - if !hasModuleConfig { + if !canRun { return nil } diff --git a/images/hooks/pkg/hooks/generate-secret-for-dvcr/hook.go b/images/hooks/pkg/hooks/generate-secret-for-dvcr/hook.go index b68ce8de42..a64c2deb4d 100644 --- a/images/hooks/pkg/hooks/generate-secret-for-dvcr/hook.go +++ b/images/hooks/pkg/hooks/generate-secret-for-dvcr/hook.go @@ -74,11 +74,11 @@ var configDVCRSecrets = &pkg.HookConfig{ } func handlerDVCRSecrets(ctx context.Context, input *pkg.HookInput) error { - hasModuleConfig, err := settings.HasModuleConfig(ctx, input) + canRun, err := settings.CanRunWithModuleConfig(ctx, input) if err != nil { return err } - if !hasModuleConfig { + if !canRun { return nil } diff --git a/images/hooks/pkg/hooks/tls-certificates-api-proxy/main.go b/images/hooks/pkg/hooks/tls-certificates-api-proxy/main.go index f444398ada..79b1942ca3 100644 --- a/images/hooks/pkg/hooks/tls-certificates-api-proxy/main.go +++ b/images/hooks/pkg/hooks/tls-certificates-api-proxy/main.go @@ -36,12 +36,12 @@ var conf = tlscertificate.GenSelfSignedTLSHookConf{ CommonCAValuesPath: fmt.Sprintf("%s.internal.rootCA", settings.ModuleName), Usages: []v1.KeyUsage{v1.UsageClientAuth}, BeforeHookCheck: func(input *pkg.HookInput) bool { - hasModuleConfig, err := settings.HasModuleConfig(context.Background(), input) + canRun, err := settings.CanRunWithModuleConfig(context.Background(), input) if err != nil { input.Logger.Error("Check module config before API proxy TLS hook", "error", err) return false } - return hasModuleConfig + return canRun }, } diff --git a/images/hooks/pkg/hooks/tls-certificates-api/main.go b/images/hooks/pkg/hooks/tls-certificates-api/main.go index 95eecc1aa6..3531010e77 100644 --- a/images/hooks/pkg/hooks/tls-certificates-api/main.go +++ b/images/hooks/pkg/hooks/tls-certificates-api/main.go @@ -43,12 +43,12 @@ var conf = tlscertificate.GenSelfSignedTLSHookConf{ FullValuesPathPrefix: fmt.Sprintf("%s.internal.apiserver.cert", settings.ModuleName), CommonCAValuesPath: fmt.Sprintf("%s.internal.rootCA", settings.ModuleName), BeforeHookCheck: func(input *pkg.HookInput) bool { - hasModuleConfig, err := settings.HasModuleConfig(context.Background(), input) + canRun, err := settings.CanRunWithModuleConfig(context.Background(), input) if err != nil { input.Logger.Error("Check module config before API TLS hook", "error", err) return false } - return hasModuleConfig + return canRun }, } diff --git a/images/hooks/pkg/hooks/tls-certificates-audit/hook.go b/images/hooks/pkg/hooks/tls-certificates-audit/hook.go index 5c547a3090..23120dfb4a 100644 --- a/images/hooks/pkg/hooks/tls-certificates-audit/hook.go +++ b/images/hooks/pkg/hooks/tls-certificates-audit/hook.go @@ -41,11 +41,11 @@ var conf = tlscertificate.GenSelfSignedTLSHookConf{ var genSelfSignedTLS = func(conf tlscertificate.GenSelfSignedTLSHookConf) pkg.ReconcileFunc { return func(ctx context.Context, input *pkg.HookInput) error { - hasModuleConfig, err := settings.HasModuleConfig(ctx, input) + canRun, err := settings.CanRunWithModuleConfig(ctx, input) if err != nil { return err } - if !hasModuleConfig { + if !canRun { return nil } diff --git a/images/hooks/pkg/hooks/tls-certificates-controller/hook.go b/images/hooks/pkg/hooks/tls-certificates-controller/hook.go index d92f278b58..5c72cafd95 100644 --- a/images/hooks/pkg/hooks/tls-certificates-controller/hook.go +++ b/images/hooks/pkg/hooks/tls-certificates-controller/hook.go @@ -43,12 +43,12 @@ var conf = tlscertificate.GenSelfSignedTLSHookConf{ FullValuesPathPrefix: fmt.Sprintf("%s.internal.controller.cert", settings.ModuleName), CommonCAValuesPath: fmt.Sprintf("%s.internal.rootCA", settings.ModuleName), BeforeHookCheck: func(input *pkg.HookInput) bool { - hasModuleConfig, err := settings.HasModuleConfig(context.Background(), input) + canRun, err := settings.CanRunWithModuleConfig(context.Background(), input) if err != nil { input.Logger.Error("Check module config before controller TLS hook", "error", err) return false } - return hasModuleConfig + return canRun }, } diff --git a/images/hooks/pkg/hooks/tls-certificates-dvcr/hook.go b/images/hooks/pkg/hooks/tls-certificates-dvcr/hook.go index 2bee3ac415..493c5b5a31 100644 --- a/images/hooks/pkg/hooks/tls-certificates-dvcr/hook.go +++ b/images/hooks/pkg/hooks/tls-certificates-dvcr/hook.go @@ -52,12 +52,12 @@ var _ = tlscertificate.RegisterInternalTLSHookEM(tlscertificate.GenSelfSignedTLS CommonCAValuesPath: fmt.Sprintf("%s.internal.rootCA", settings.ModuleName), BeforeHookCheck: func(input *pkg.HookInput) bool { - hasModuleConfig, err := settings.HasModuleConfig(context.Background(), input) + canRun, err := settings.CanRunWithModuleConfig(context.Background(), input) if err != nil { input.Logger.Error("Check module config before DVCR TLS hook", "error", err) return false } - if !hasModuleConfig { + if !canRun { return false } diff --git a/images/hooks/pkg/hooks/tls-certificates-dvcr/hook_test.go b/images/hooks/pkg/hooks/tls-certificates-dvcr/hook_test.go index d483d5dbc8..c186687048 100644 --- a/images/hooks/pkg/hooks/tls-certificates-dvcr/hook_test.go +++ b/images/hooks/pkg/hooks/tls-certificates-dvcr/hook_test.go @@ -46,7 +46,7 @@ func TestBeforeHookCheckSkipsWithoutModuleConfig(t *testing.T) { return nil }}, nil) - ok, err := settings.HasModuleConfig(context.Background(), &pkg.HookInput{DC: dc}) + ok, err := settings.CanRunWithModuleConfig(context.Background(), &pkg.HookInput{DC: dc}) if err != nil { t.Fatalf("unexpected error: %v", err) } diff --git a/images/hooks/pkg/settings/module_config.go b/images/hooks/pkg/settings/module_config.go index 6129dd1b87..35316f4f82 100644 --- a/images/hooks/pkg/settings/module_config.go +++ b/images/hooks/pkg/settings/module_config.go @@ -28,11 +28,15 @@ import ( mcapi "github.com/deckhouse/virtualization-controller/pkg/controller/moduleconfig/api" ) -func HasModuleConfig(ctx context.Context, input *pkg.HookInput) (bool, error) { +func CanRunWithModuleConfig(ctx context.Context, input *pkg.HookInput) (bool, error) { if input == nil || input.DC == nil { return false, fmt.Errorf("dependency container is nil") } + if input.Values != nil && input.Values.Get(InternalValuesConfigCopyPath).Exists() { + return true, nil + } + k8sClient, err := input.DC.GetK8sClient(addModuleConfigScheme()) if err != nil { return false, fmt.Errorf("get kubernetes client: %w", err) diff --git a/images/hooks/pkg/settings/module_config_test.go b/images/hooks/pkg/settings/module_config_test.go index 6d60118e8a..782155401b 100644 --- a/images/hooks/pkg/settings/module_config_test.go +++ b/images/hooks/pkg/settings/module_config_test.go @@ -25,6 +25,7 @@ import ( ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" "github.com/deckhouse/module-sdk/pkg" + patchablevalues "github.com/deckhouse/module-sdk/pkg/patchable-values" "github.com/deckhouse/module-sdk/testing/mock" mcapi "github.com/deckhouse/virtualization-controller/pkg/controller/moduleconfig/api" ) @@ -38,24 +39,47 @@ func (f *fakeKubernetesClient) Get(ctx context.Context, key ctrlclient.ObjectKey return f.get(ctx, key, obj) } -func TestHasModuleConfig(t *testing.T) { +func TestCanRunWithModuleConfig(t *testing.T) { newInput := func(client pkg.KubernetesClient, err error) *pkg.HookInput { dc := mock.NewDependencyContainerMock(t) dc.GetK8sClientMock.Return(client, err) return &pkg.HookInput{DC: dc} } + t.Run("returns true when internal values copy exists", func(t *testing.T) { + dc := mock.NewDependencyContainerMock(t) + values, err := patchablevalues.NewPatchableValues(map[string]any{ + "virtualization": map[string]any{ + "internal": map[string]any{ + "moduleConfig": map[string]any{}, + }, + }, + }) + if err != nil { + t.Fatalf("create patchable values: %v", err) + } + + input := &pkg.HookInput{DC: dc, Values: values} + ok, err := CanRunWithModuleConfig(context.Background(), input) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !ok { + t.Fatalf("expected CanRunWithModuleConfig to return true") + } + }) + t.Run("returns false when module config does not exist", func(t *testing.T) { input := newInput(&fakeKubernetesClient{get: func(ctx context.Context, key ctrlclient.ObjectKey, obj ctrlclient.Object) error { return apierrors.NewNotFound(schema.GroupResource{Group: "deckhouse.io", Resource: "moduleconfigs"}, ModuleName) }}, nil) - ok, err := HasModuleConfig(context.Background(), input) + ok, err := CanRunWithModuleConfig(context.Background(), input) if err != nil { t.Fatalf("unexpected error: %v", err) } if ok { - t.Fatalf("expected HasModuleConfig to return false") + t.Fatalf("expected CanRunWithModuleConfig to return false") } }) @@ -66,12 +90,12 @@ func TestHasModuleConfig(t *testing.T) { return nil }}, nil) - ok, err := HasModuleConfig(context.Background(), input) + ok, err := CanRunWithModuleConfig(context.Background(), input) if err != nil { t.Fatalf("unexpected error: %v", err) } if ok { - t.Fatalf("expected HasModuleConfig to return false") + t.Fatalf("expected CanRunWithModuleConfig to return false") } }) @@ -82,12 +106,12 @@ func TestHasModuleConfig(t *testing.T) { return nil }}, nil) - ok, err := HasModuleConfig(context.Background(), input) + ok, err := CanRunWithModuleConfig(context.Background(), input) if err != nil { t.Fatalf("unexpected error: %v", err) } if ok { - t.Fatalf("expected HasModuleConfig to return false") + t.Fatalf("expected CanRunWithModuleConfig to return false") } }) @@ -101,24 +125,24 @@ func TestHasModuleConfig(t *testing.T) { return nil }}, nil) - ok, err := HasModuleConfig(context.Background(), input) + ok, err := CanRunWithModuleConfig(context.Background(), input) if err != nil { t.Fatalf("unexpected error: %v", err) } if !ok { - t.Fatalf("expected HasModuleConfig to return true") + t.Fatalf("expected CanRunWithModuleConfig to return true") } }) t.Run("returns error when kubernetes client cannot be created", func(t *testing.T) { input := newInput(nil, staticError("boom")) - ok, err := HasModuleConfig(context.Background(), input) + ok, err := CanRunWithModuleConfig(context.Background(), input) if err == nil { t.Fatalf("expected error") } if ok { - t.Fatalf("expected HasModuleConfig to return false") + t.Fatalf("expected CanRunWithModuleConfig to return false") } }) } From a1590ef81923a163e1e7833fb76b7da7b2628870 Mon Sep 17 00:00:00 2001 From: Dmitry Lopatin Date: Wed, 22 Apr 2026 13:39:43 +0300 Subject: [PATCH 7/7] fix after review Signed-off-by: Dmitry Lopatin --- .../pkg/hooks/discovery-clusterip-service-for-dvcr/hook_test.go | 1 + images/hooks/pkg/hooks/discovery-workload-nodes/hook_test.go | 2 ++ images/hooks/pkg/hooks/generate-secret-for-dvcr/hook_test.go | 1 + 3 files changed, 4 insertions(+) diff --git a/images/hooks/pkg/hooks/discovery-clusterip-service-for-dvcr/hook_test.go b/images/hooks/pkg/hooks/discovery-clusterip-service-for-dvcr/hook_test.go index 4291b28184..a6d258cb3f 100644 --- a/images/hooks/pkg/hooks/discovery-clusterip-service-for-dvcr/hook_test.go +++ b/images/hooks/pkg/hooks/discovery-clusterip-service-for-dvcr/hook_test.go @@ -48,6 +48,7 @@ var _ = Describe("DiscoveryClusterIPServiceForDVCR", func() { dc = mock.NewDependencyContainerMock(GinkgoT()) snapshots = mock.NewSnapshotsMock(GinkgoT()) values = mock.NewPatchableValuesCollectorMock(GinkgoT()) + values.GetMock.When(settings.InternalValuesConfigCopyPath).Then(gjson.Result{}) }) AfterEach(func() { diff --git a/images/hooks/pkg/hooks/discovery-workload-nodes/hook_test.go b/images/hooks/pkg/hooks/discovery-workload-nodes/hook_test.go index 91ede8638e..9267ad3d35 100644 --- a/images/hooks/pkg/hooks/discovery-workload-nodes/hook_test.go +++ b/images/hooks/pkg/hooks/discovery-workload-nodes/hook_test.go @@ -22,6 +22,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "github.com/tidwall/gjson" ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" "github.com/deckhouse/deckhouse/pkg/log" @@ -74,6 +75,7 @@ var _ = Describe("DiscoveryWorkloadNodes", func() { dc = mock.NewDependencyContainerMock(GinkgoT()) snapshots = mock.NewSnapshotsMock(GinkgoT()) values = mock.NewPatchableValuesCollectorMock(GinkgoT()) + values.GetMock.When(settings.InternalValuesConfigCopyPath).Then(gjson.Result{}) }) AfterEach(func() { diff --git a/images/hooks/pkg/hooks/generate-secret-for-dvcr/hook_test.go b/images/hooks/pkg/hooks/generate-secret-for-dvcr/hook_test.go index 54b199c24c..58abc79085 100644 --- a/images/hooks/pkg/hooks/generate-secret-for-dvcr/hook_test.go +++ b/images/hooks/pkg/hooks/generate-secret-for-dvcr/hook_test.go @@ -90,6 +90,7 @@ var _ = Describe("DVCR Secrets", func() { dc = mock.NewDependencyContainerMock(GinkgoT()) snapshots = mock.NewSnapshotsMock(GinkgoT()) values = mock.NewPatchableValuesCollectorMock(GinkgoT()) + values.GetMock.When(settings.InternalValuesConfigCopyPath).Then(gjson.Result{}) }) AfterEach(func() {