diff --git a/go.mod b/go.mod index ccb2b0e6..9ee7fea5 100644 --- a/go.mod +++ b/go.mod @@ -36,6 +36,7 @@ require ( k8s.io/component-base v0.29.3 k8s.io/klog/v2 v2.120.1 k8s.io/kubectl v0.29.3 + k8s.io/utils v0.0.0-20240310230437-4693a0247e57 sigs.k8s.io/yaml v1.4.0 ) @@ -562,7 +563,6 @@ require ( k8s.io/klog v1.0.0 // indirect k8s.io/kube-openapi v0.0.0-20240105020646-a37d4de58910 // indirect k8s.io/metrics v0.29.3 // indirect - k8s.io/utils v0.0.0-20240310230437-4693a0247e57 // indirect kubevirt.io/api v1.2.0 // indirect kubevirt.io/containerized-data-importer-api v1.57.0-alpha1 // indirect kubevirt.io/controller-lifecycle-operator-sdk/api v0.0.0-20220329064328-f3cc58c6ed90 // indirect diff --git a/internal/platform/cmd/edit/editconfig/editconfig.go b/internal/platform/cmd/edit/editconfig/editconfig.go index 29a20f2f..914b7f86 100644 --- a/internal/platform/cmd/edit/editconfig/editconfig.go +++ b/internal/platform/cmd/edit/editconfig/editconfig.go @@ -69,8 +69,7 @@ func BaseEditConfigCMD(cmd *cobra.Command, name, secret, dataKey string) error { encodedValue, err := encodeSecretTmp(updatedContent, dataKey) _, err = kubeCl.CoreV1(). - Secrets("kube-system"). - Patch(context.TODO(), secret, types.MergePatchType, encodedValue, metav1.PatchOptions{}) + Secrets("kube-system").Patch(context.TODO(), secret, types.MergePatchType, encodedValue, metav1.PatchOptions{}) if err != nil { return fmt.Errorf("Error updating secret: %w", err) } diff --git a/internal/platform/cmd/module/disable/disable.go b/internal/platform/cmd/module/disable/disable.go new file mode 100644 index 00000000..6a55c04e --- /dev/null +++ b/internal/platform/cmd/module/disable/disable.go @@ -0,0 +1,69 @@ +/* +Copyright 2025 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 disable + +import ( + "fmt" + "github.com/deckhouse/deckhouse-cli/internal/platform/cmd/module/operatemodule" + "github.com/deckhouse/deckhouse-cli/internal/utilk8s" + "k8s.io/client-go/dynamic" + + "github.com/deckhouse/deckhouse-cli/internal/platform/cmd/edit/flags" + "github.com/spf13/cobra" + "k8s.io/kubectl/pkg/util/templates" +) + +var disableLong = templates.LongDesc(` +Disable module using the ModuleConfig resource. + +© Flant JSC 2025`) + +func NewCommand() *cobra.Command { + disableCmd := &cobra.Command{ + Use: "disable", + Short: "Disable module.", + Long: disableLong, + ValidArgs: []string{"module_name"}, + SilenceErrors: true, + SilenceUsage: true, + RunE: disableModule, + } + flags.AddFlags(disableCmd.Flags()) + return disableCmd +} + +func disableModule(cmd *cobra.Command, moduleName []string) error { + kubeconfigPath, err := cmd.Flags().GetString("kubeconfig") + if err != nil { + return fmt.Errorf("Failed to setup Kubernetes client: %w", err) + } + + config, _, err := utilk8s.SetupK8sClientSet(kubeconfigPath) + if err != nil { + return fmt.Errorf("Failed to setup Kubernetes client: %w", err) + } + dynamicClient, err := dynamic.NewForConfig(config) + if err != nil { + return fmt.Errorf("Failed to create dynamic client: %v", err) + } + err = operatemodule.OperateModule(dynamicClient, moduleName[0], operatemodule.ModuleDisabled) + if err != nil { + return fmt.Errorf("Error disable module: %w", err) + } + fmt.Printf("Module %s disabled\n", moduleName[0]) + return err +} diff --git a/internal/platform/cmd/module/enable/enable.go b/internal/platform/cmd/module/enable/enable.go new file mode 100644 index 00000000..fd786d91 --- /dev/null +++ b/internal/platform/cmd/module/enable/enable.go @@ -0,0 +1,70 @@ +/* +Copyright 2025 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 enable + +import ( + "fmt" + "github.com/deckhouse/deckhouse-cli/internal/platform/cmd/module/operatemodule" + "github.com/deckhouse/deckhouse-cli/internal/utilk8s" + "k8s.io/client-go/dynamic" + + "github.com/deckhouse/deckhouse-cli/internal/platform/cmd/edit/flags" + "github.com/spf13/cobra" + "k8s.io/kubectl/pkg/util/templates" +) + +var enableLong = templates.LongDesc(` +Enable module using the ModuleConfig resource. + +© Flant JSC 2025`) + +func NewCommand() *cobra.Command { + enableCmd := &cobra.Command{ + Use: "enable", + Short: "Enable module.", + Long: enableLong, + ValidArgs: []string{"module_name"}, + SilenceErrors: true, + SilenceUsage: true, + RunE: enableModule, + } + flags.AddFlags(enableCmd.Flags()) + return enableCmd +} + +func enableModule(cmd *cobra.Command, moduleName []string) error { + kubeconfigPath, err := cmd.Flags().GetString("kubeconfig") + if err != nil { + return fmt.Errorf("Failed to setup Kubernetes client: %w", err) + } + + config, _, err := utilk8s.SetupK8sClientSet(kubeconfigPath) + if err != nil { + return fmt.Errorf("Failed to setup Kubernetes client: %w", err) + } + + dynamicClient, err := dynamic.NewForConfig(config) + if err != nil { + return fmt.Errorf("Failed to create dynamic client: %v", err) + } + err = operatemodule.OperateModule(dynamicClient, moduleName[0], operatemodule.ModuleEnabled) + if err != nil { + return fmt.Errorf("Error enable module: %w", err) + } + fmt.Printf("Module %s enabled\n", moduleName[0]) + return err +} diff --git a/internal/platform/cmd/module/flags/flags.go b/internal/platform/cmd/module/flags/flags.go new file mode 100644 index 00000000..6c65c8f7 --- /dev/null +++ b/internal/platform/cmd/module/flags/flags.go @@ -0,0 +1,29 @@ +/* +Copyright 2025 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 flags + +import ( + "github.com/spf13/pflag" +) + +func AddFlags(flagSet *pflag.FlagSet) { + flagSet.StringP( + "editor", "e", + "vi", + "Your favourite editor.", + ) +} diff --git a/internal/platform/cmd/module/list/list.go b/internal/platform/cmd/module/list/list.go new file mode 100644 index 00000000..30908aea --- /dev/null +++ b/internal/platform/cmd/module/list/list.go @@ -0,0 +1,63 @@ +/* +Copyright 2025 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 list + +import ( + "fmt" + "github.com/deckhouse/deckhouse-cli/internal/platform/cmd/module/operatemodule" + "github.com/deckhouse/deckhouse-cli/internal/utilk8s" + + "github.com/deckhouse/deckhouse-cli/internal/platform/cmd/edit/flags" + "github.com/spf13/cobra" + "k8s.io/kubectl/pkg/util/templates" +) + +var listLong = templates.LongDesc(` +List enabled Deckhouse Kubernetes Platform modules. + +© Flant JSC 2025`) + +func NewCommand() *cobra.Command { + listCmd := &cobra.Command{ + Use: "list", + Short: "List enabled modules.", + Long: listLong, + SilenceErrors: true, + SilenceUsage: true, + RunE: listModule, + } + flags.AddFlags(listCmd.Flags()) + return listCmd +} + +func listModule(cmd *cobra.Command, args []string) error { + kubeconfigPath, err := cmd.Flags().GetString("kubeconfig") + if err != nil { + return fmt.Errorf("Failed to setup Kubernetes client: %w", err) + } + + config, kubeCl, err := utilk8s.SetupK8sClientSet(kubeconfigPath) + if err != nil { + return fmt.Errorf("Failed to setup Kubernetes client: %w", err) + } + + err = operatemodule.OptionsModule(config, kubeCl, "list.yaml") + if err != nil { + return fmt.Errorf("Error list modules: %w", err) + } + return err +} diff --git a/internal/platform/cmd/module/module.go b/internal/platform/cmd/module/module.go new file mode 100644 index 00000000..db287dc0 --- /dev/null +++ b/internal/platform/cmd/module/module.go @@ -0,0 +1,53 @@ +/* +Copyright 2025 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 module + +import ( + "github.com/deckhouse/deckhouse-cli/internal/platform/cmd/module/enable" + "github.com/deckhouse/deckhouse-cli/internal/platform/cmd/module/list" + "github.com/deckhouse/deckhouse-cli/internal/platform/cmd/module/snapshots" + "github.com/deckhouse/deckhouse-cli/internal/platform/cmd/module/values" + "github.com/spf13/cobra" + "k8s.io/kubectl/pkg/util/templates" + + "github.com/deckhouse/deckhouse-cli/internal/platform/cmd/module/disable" + "github.com/deckhouse/deckhouse-cli/internal/platform/cmd/module/flags" +) + +var moduleLong = templates.LongDesc(` +Operate the Deckhouse Kubernetes Platform modules. + +© Flant JSC 2025`) + +func NewCommand() *cobra.Command { + moduleCmd := &cobra.Command{ + Use: "module", Short: "Operate the Deckhouse Kubernetes Platform modules", + Long: moduleLong, + } + + moduleCmd.AddCommand( + enable.NewCommand(), + disable.NewCommand(), + list.NewCommand(), + values.NewCommand(), + snapshots.NewCommand(), + ) + + flags.AddFlags(moduleCmd.Flags()) + + return moduleCmd +} diff --git a/internal/platform/cmd/module/operatemodule/optionsmodule.go b/internal/platform/cmd/module/operatemodule/optionsmodule.go new file mode 100644 index 00000000..d298347b --- /dev/null +++ b/internal/platform/cmd/module/operatemodule/optionsmodule.go @@ -0,0 +1,91 @@ +package operatemodule + +import ( + "bytes" + "context" + "fmt" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/remotecommand" +) + +func OptionsModule(config *rest.Config, kubeCl kubernetes.Interface, pathFromOption string) error { + const ( + apiProtocol = "http" + apiEndpoint = "127.0.0.1" + apiPort = "9652" + modulePath = "module" + + labelSelector = "leader=true" + namespace = "d8-system" + containerName = "deckhouse" + ) + + fullEndpointUrl := fmt.Sprintf("%s://%s:%s/%s/%s", apiProtocol, apiEndpoint, apiPort, modulePath, pathFromOption) + getApi := []string{"curl", fullEndpointUrl} + podName, err := getDeckhousePod(kubeCl, namespace, labelSelector) + executor, err := execInPod(config, kubeCl, getApi, podName, namespace, containerName) + + var stdout bytes.Buffer + var stderr bytes.Buffer + if err = executor.StreamWithContext( + context.Background(), + remotecommand.StreamOptions{ + Stdout: &stdout, + Stderr: &stderr, + }); err != nil { + return err + } + + fmt.Printf("%s\n", stdout.String()) + return err +} + +func getDeckhousePod(kubeCl kubernetes.Interface, namespace string, labelSelector string) (string, error) { + pods, err := kubeCl.CoreV1().Pods(namespace).List(context.Background(), metav1.ListOptions{ + LabelSelector: labelSelector, + }) + if err != nil { + return "", fmt.Errorf("Error listing pods: %w", err) + } + + if len(pods.Items) == 0 { + return "", fmt.Errorf("No pods found with the label: %s", labelSelector) + } + + pod := pods.Items[0] + podName := pod.Name + return podName, nil +} + +func execInPod(config *rest.Config, kubeCl kubernetes.Interface, getApi []string, podName string, namespace string, containerName string) (remotecommand.Executor, error) { + scheme := runtime.NewScheme() + parameterCodec := runtime.NewParameterCodec(scheme) + if err := v1.AddToScheme(scheme); err != nil { + return nil, fmt.Errorf("Failed to create parameter codec: %w", err) + } + + req := kubeCl.CoreV1().RESTClient(). + Post(). + Resource("pods"). + Name(podName). + Namespace(namespace). + SubResource("exec"). + VersionedParams(&v1.PodExecOptions{ + Command: getApi, + Container: containerName, + Stdin: false, + Stdout: true, + Stderr: true, + TTY: false, + }, parameterCodec) + + executor, err := remotecommand.NewSPDYExecutor(config, "POST", req.URL()) + if err != nil { + return nil, fmt.Errorf("Creating SPDY executor for Pod %s: %v", podName, err) + } + return executor, nil +} diff --git a/internal/platform/cmd/module/operatemodule/switchmodule.go b/internal/platform/cmd/module/operatemodule/switchmodule.go new file mode 100644 index 00000000..8b649e0a --- /dev/null +++ b/internal/platform/cmd/module/operatemodule/switchmodule.go @@ -0,0 +1,86 @@ +package operatemodule + +import ( + "context" + "encoding/json" + "fmt" + "github.com/deckhouse/deckhouse-cli/internal/platform/cmd/module/v1alpha1" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/dynamic" + "k8s.io/utils/ptr" +) + +type ModuleState string + +const ( + ModuleEnabled ModuleState = "enabled" + ModuleDisabled ModuleState = "disabled" +) + +func OperateModule(dynamicClient dynamic.Interface, name string, moduleState ModuleState) error { + resourceClient := dynamicClient.Resource( + schema.GroupVersionResource{ + Group: "deckhouse.io", + Version: "v1alpha1", + Resource: "moduleconfigs", + }, + ) + + customResource, err := resourceClient.Get(context.TODO(), name, metav1.GetOptions{}) + if err != nil && !errors.IsNotFound(err) { + return err + } + enabledSpec, err := patchSpec(moduleState) + if customResource != nil { + if _, err = resourceClient.Patch(context.TODO(), name, types.MergePatchType, enabledSpec, metav1.PatchOptions{}); err != nil { + return fmt.Errorf("failed to update the '%s' module config: %w", name, err) + } + return nil + } + + obj, err := createModuleConfig(name, moduleState) + if err != nil { + return fmt.Errorf("failed to convert the '%s' module config: %w", name, err) + } + if _, err = resourceClient.Create(context.TODO(), obj, metav1.CreateOptions{}); err != nil { + return fmt.Errorf("failed to create the '%s' module config: %w", name, err) + } + return err +} + +func createModuleConfig(name string, moduleState ModuleState) (*unstructured.Unstructured, error) { + newCfg := &v1alpha1.ModuleConfigMeta{ + TypeMeta: metav1.TypeMeta{ + Kind: "ModuleConfig", + APIVersion: "deckhouse.io/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: name, + }, + Spec: v1alpha1.ModuleConfigSpec{ + Enabled: ptr.To(moduleState == ModuleEnabled), + }, + } + content, err := runtime.DefaultUnstructuredConverter.ToUnstructured(newCfg) + return &unstructured.Unstructured{Object: content}, err +} + +func patchSpec(moduleState ModuleState) ([]byte, error) { + patchData := map[string]interface{}{ + "spec": map[string]interface{}{ + "enabled": moduleState == ModuleEnabled, + }, + } + + patchBytes, err := json.Marshal(patchData) + if err != nil { + return nil, fmt.Errorf("Error convert to json updated data: %w", err) + } + + return patchBytes, nil +} diff --git a/internal/platform/cmd/module/operatemodule/switchmodule_test.go b/internal/platform/cmd/module/operatemodule/switchmodule_test.go new file mode 100644 index 00000000..32652252 --- /dev/null +++ b/internal/platform/cmd/module/operatemodule/switchmodule_test.go @@ -0,0 +1,62 @@ +package operatemodule + +import ( + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/dynamic" + "k8s.io/client-go/dynamic/fake" + + "testing" +) + +func TestOperateModule(t *testing.T) { + type args struct { + dynamicClient dynamic.Interface + name string + moduleState ModuleState + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "check enabled test", + args: args{ + dynamicClient: fake.NewSimpleDynamicClient(runtime.NewScheme(), &unstructured.Unstructured{Object: map[string]interface{}{ + "apiVersion": "deckhouse.io/v1alpha1", + "kind": "ModuleConfig", + "metadata": map[string]any{"name": "stronghold", "namespace": ""}, + "spec": map[string]interface{}{ + "enabled": false, + }, + }}), + name: "stronghold", + moduleState: ModuleEnabled, + }, + }, + { + name: "check not exist module", + wantErr: false, + args: args{ + dynamicClient: fake.NewSimpleDynamicClient(runtime.NewScheme(), &unstructured.Unstructured{Object: map[string]interface{}{ + "apiVersion": "deckhouse.io/v1alpha1", + "kind": "ModuleConfig", + "metadata": map[string]any{"name": "deckhouse", "namespace": ""}, + "spec": map[string]interface{}{ + "enabled": false, + }, + }}), + name: "stronghold", + moduleState: ModuleEnabled, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := OperateModule(tt.args.dynamicClient, tt.args.name, tt.args.moduleState); (err != nil) != tt.wantErr { + t.Errorf("OperateModule() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} diff --git a/internal/platform/cmd/module/snapshots/snapshots.go b/internal/platform/cmd/module/snapshots/snapshots.go new file mode 100644 index 00000000..03b4057a --- /dev/null +++ b/internal/platform/cmd/module/snapshots/snapshots.go @@ -0,0 +1,64 @@ +/* +Copyright 2025 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 snapshots + +import ( + "fmt" + "github.com/deckhouse/deckhouse-cli/internal/platform/cmd/module/operatemodule" + "github.com/deckhouse/deckhouse-cli/internal/utilk8s" + + "github.com/deckhouse/deckhouse-cli/internal/platform/cmd/edit/flags" + "github.com/spf13/cobra" + "k8s.io/kubectl/pkg/util/templates" +) + +var snapshotsLong = templates.LongDesc(` +Dump module hooks snapshots. + +© Flant JSC 2025`) + +func NewCommand() *cobra.Command { + snapshotsCmd := &cobra.Command{ + Use: "snapshots", + Short: "Dump shapshots.", + Long: snapshotsLong, + ValidArgs: []string{"module_name"}, + SilenceErrors: true, + SilenceUsage: true, + RunE: snapshotsModule, + } + flags.AddFlags(snapshotsCmd.Flags()) + return snapshotsCmd +} + +func snapshotsModule(cmd *cobra.Command, moduleName []string) error { + kubeconfigPath, err := cmd.Flags().GetString("kubeconfig") + if err != nil { + return fmt.Errorf("Failed to setup Kubernetes client: %w", err) + } + + config, kubeCl, err := utilk8s.SetupK8sClientSet(kubeconfigPath) + if err != nil { + return fmt.Errorf("Failed to setup Kubernetes client: %w", err) + } + pathFromOption := fmt.Sprintf("%s/snapshots.yaml", moduleName[0]) + err = operatemodule.OptionsModule(config, kubeCl, pathFromOption) + if err != nil { + return fmt.Errorf("Error snapshot module: %w", err) + } + return err +} diff --git a/internal/platform/cmd/module/v1alpha1/v1alpha1.go b/internal/platform/cmd/module/v1alpha1/v1alpha1.go new file mode 100644 index 00000000..cc3ecf29 --- /dev/null +++ b/internal/platform/cmd/module/v1alpha1/v1alpha1.go @@ -0,0 +1,30 @@ +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +type ModuleConfigMeta struct { + metav1.TypeMeta `json:",inline"` + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + Spec ModuleConfigSpec `json:"spec"` + Status ModuleConfigStatus `json:"status,omitempty"` +} + +type ModuleConfigSpec struct { + Version int `json:"version,omitempty"` + Settings SettingsValues `json:"settings,omitempty"` + Enabled *bool `json:"enabled,omitempty"` + UpdatePolicy string `json:"updatePolicy,omitempty"` + Source string `json:"source,omitempty"` +} + +type ModuleConfigStatus struct { + Version string `json:"version"` + Message string `json:"message"` +} + +type SettingsValues map[string]interface{} diff --git a/internal/platform/cmd/module/values/values.go b/internal/platform/cmd/module/values/values.go new file mode 100644 index 00000000..daf9a870 --- /dev/null +++ b/internal/platform/cmd/module/values/values.go @@ -0,0 +1,64 @@ +/* +Copyright 2025 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 values + +import ( + "fmt" + "github.com/deckhouse/deckhouse-cli/internal/platform/cmd/edit/flags" + "github.com/deckhouse/deckhouse-cli/internal/platform/cmd/module/operatemodule" + "github.com/deckhouse/deckhouse-cli/internal/utilk8s" + "github.com/spf13/cobra" + "k8s.io/kubectl/pkg/util/templates" +) + +var valuesLong = templates.LongDesc(` +Dump module hooks values. + +© Flant JSC 2025`) + +func NewCommand() *cobra.Command { + valuesCmd := &cobra.Command{ + Use: "values", + Short: "Dump values.", + Long: valuesLong, + ValidArgs: []string{"module_name"}, + SilenceErrors: true, + SilenceUsage: true, + RunE: valuesModule, + } + flags.AddFlags(valuesCmd.Flags()) + return valuesCmd +} + +func valuesModule(cmd *cobra.Command, moduleName []string) error { + kubeconfigPath, err := cmd.Flags().GetString("kubeconfig") + if err != nil { + return fmt.Errorf("Failed to setup Kubernetes client: %w", err) + } + + config, kubeCl, err := utilk8s.SetupK8sClientSet(kubeconfigPath) + if err != nil { + return fmt.Errorf("Failed to setup Kubernetes client: %w", err) + } + + pathFromOption := fmt.Sprintf("%s/values.yaml", moduleName[0]) + err = operatemodule.OptionsModule(config, kubeCl, pathFromOption) + if err != nil { + return fmt.Errorf("Error print values: %w", err) + } + return err +} diff --git a/internal/platform/cmd/platform.go b/internal/platform/cmd/platform.go index 9706e44e..57410eb5 100644 --- a/internal/platform/cmd/platform.go +++ b/internal/platform/cmd/platform.go @@ -1,5 +1,5 @@ /* -Copyright 2024 Flant JSC +Copyright 2025 Flant JSC Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -21,18 +21,19 @@ import ( "k8s.io/kubectl/pkg/util/templates" "github.com/deckhouse/deckhouse-cli/internal/platform/cmd/edit" + "github.com/deckhouse/deckhouse-cli/internal/platform/cmd/module" "github.com/deckhouse/deckhouse-cli/internal/platform/flags" ) var platformLong = templates.LongDesc(` -Operate the Deckhouse Kubernetes Platform. +Operate platform options in DKP. © Flant JSC 2025`) func NewCommand() *cobra.Command { platformCmd := &cobra.Command{ Use: "platform ", - Short: "Operate the Deckhouse Kubernetes Platform", + Short: "Operate platform options.", Aliases: []string{"p"}, Long: platformLong, PreRunE: flags.ValidateParameters, @@ -40,6 +41,7 @@ func NewCommand() *cobra.Command { platformCmd.AddCommand( edit.NewCommand(), + module.NewCommand(), ) flags.AddPersistentFlags(platformCmd)