From b244af1c7288a2acd77645375cc8dcdaa9ae7182 Mon Sep 17 00:00:00 2001 From: Smyslov Maxim Date: Fri, 26 Dec 2025 13:35:12 +0300 Subject: [PATCH 1/4] fix Signed-off-by: Smyslov Maxim --- cmd/plugins/plugins.go | 15 +++++++++++++++ pkg/registry/service/plugin_service.go | 6 ++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/cmd/plugins/plugins.go b/cmd/plugins/plugins.go index a4b75e46..c971c32e 100644 --- a/cmd/plugins/plugins.go +++ b/cmd/plugins/plugins.go @@ -19,6 +19,7 @@ package plugins import ( "context" "encoding/json" + "errors" "fmt" "log/slog" "os" @@ -76,6 +77,20 @@ func NewCommand(logger *dkplog.Logger) *cobra.Command { PersistentPreRun: func(_ *cobra.Command, _ []string) { // init plugin services for subcommands after flags are parsed pc.InitPluginServices() + + err := os.MkdirAll(flags.DeckhousePluginsDir+"/plugins", 0755) + // if permission failed + if errors.Is(err, os.ErrPermission) { + pc.logger.Warn("use homedir instead of default d8 plugins path in '/opt/deckhouse/lib/deckhouse-cli'", slog.String("new_path", flags.DeckhousePluginsDir), dkplog.Err(err)) + + flags.DeckhousePluginsDir, err = os.UserHomeDir() + if err != nil { + logger.Warn("failed to receive home dir to create plugins dir", slog.String("error", err.Error())) + return + } + + flags.DeckhousePluginsDir = path.Join(flags.DeckhousePluginsDir, ".deckhouse-cli") + } }, } diff --git a/pkg/registry/service/plugin_service.go b/pkg/registry/service/plugin_service.go index 8a88bce8..8f1523f7 100644 --- a/pkg/registry/service/plugin_service.go +++ b/pkg/registry/service/plugin_service.go @@ -81,15 +81,13 @@ func (s *PluginService) GetPluginContract(ctx context.Context, pluginName, tag s return nil, fmt.Errorf("no manifests found in index manifest") } - // hardcoded first + // hardcoded first manifest (all contracts must be the same for all manifests) digest := indexManifest.GetManifests()[0].GetDigest() if digest.String() == "" { return nil, fmt.Errorf("no digest found in manifest") } - digestClient := pluginClient.WithSegment("meta") - - digestManifestResult, err = digestClient.GetManifest(ctx, "@"+digest.String()) + digestManifestResult, err = pluginClient.GetManifest(ctx, "@"+digest.String()) if err != nil { return nil, fmt.Errorf("failed to get manifest: %w", err) } From 2f7f00a342e9ddc87c12c03f52ea38349ad4ffda Mon Sep 17 00:00:00 2001 From: Smyslov Maxim Date: Fri, 26 Dec 2025 14:29:06 +0300 Subject: [PATCH 2/4] fix Signed-off-by: Smyslov Maxim --- cmd/plugins/plugin.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/plugins/plugin.go b/cmd/plugins/plugin.go index 4cb5da1b..6bdc3139 100644 --- a/cmd/plugins/plugin.go +++ b/cmd/plugins/plugin.go @@ -106,7 +106,7 @@ func NewPluginCommand(commandName string, description string, aliases []string, return } - logger.Info("Executing plugin", slog.Any("args", args)) + logger.Debug("Executing plugin", slog.Any("args", args)) command := exec.CommandContext(cmd.Context(), absPath, args...) command.Stdout = os.Stdout From 14b308d66f594d46554beb5364c87b41b6554167 Mon Sep 17 00:00:00 2001 From: Pavel Okhlopkov Date: Fri, 26 Dec 2025 11:53:01 +0300 Subject: [PATCH 3/4] using nested string not struct Signed-off-by: Pavel Okhlopkov --- cmd/plugins/plugin.go | 20 ++++++++++---------- cmd/plugins/plugins.go | 26 ++++++++++++++------------ 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/cmd/plugins/plugin.go b/cmd/plugins/plugin.go index 6bdc3139..14e28eb2 100644 --- a/cmd/plugins/plugin.go +++ b/cmd/plugins/plugin.go @@ -28,7 +28,6 @@ import ( dkplog "github.com/deckhouse/deckhouse/pkg/log" - "github.com/deckhouse/deckhouse-cli/cmd/plugins/flags" "github.com/deckhouse/deckhouse-cli/pkg/registry/service" ) @@ -41,7 +40,7 @@ const ( func NewPluginCommand(commandName string, description string, aliases []string, logger *dkplog.Logger) *cobra.Command { pc := NewPluginsCommand(logger.Named("plugins-command")) - pluginContractFilePath := path.Join(flags.DeckhousePluginsDir, "cache", "contracts", "system.json") + pluginContractFilePath := path.Join(pc.pluginDirectory, "cache", "contracts", "system.json") pluginContract, err := service.GetPluginContractFromFile(pluginContractFilePath) if err != nil { logger.Debug("failed to get plugin contract from cache", slog.String("error", err.Error())) @@ -53,18 +52,18 @@ func NewPluginCommand(commandName string, description string, aliases []string, // to check we can create directories here // we try to create root plugins folder - err = os.MkdirAll(flags.DeckhousePluginsDir+"/plugins", 0755) + err = os.MkdirAll(pc.pluginDirectory+"/plugins", 0755) // if permission failed if errors.Is(err, os.ErrPermission) { - pc.logger.Warn("use homedir instead of default d8 plugins path in '/opt/deckhouse/lib/deckhouse-cli'", slog.String("new_path", flags.DeckhousePluginsDir), dkplog.Err(err)) + pc.logger.Warn("use homedir instead of default d8 plugins path in '/opt/deckhouse/lib/deckhouse-cli'", slog.String("new_path", pc.pluginDirectory), dkplog.Err(err)) - flags.DeckhousePluginsDir, err = os.UserHomeDir() + pc.pluginDirectory, err = os.UserHomeDir() if err != nil { logger.Warn("failed to receive home dir to create plugins dir", slog.String("error", err.Error())) return nil } - flags.DeckhousePluginsDir = path.Join(flags.DeckhousePluginsDir, ".deckhouse-cli") + pc.pluginDirectory = path.Join(pc.pluginDirectory, ".deckhouse-cli") } if err != nil { @@ -83,11 +82,12 @@ func NewPluginCommand(commandName string, description string, aliases []string, pc.InitPluginServices() }, Run: func(cmd *cobra.Command, args []string) { - installed, err := checkInstalled(commandName) + installed, err := pc.checkInstalled(commandName) if err != nil { fmt.Println("Error checking installed:", err) return } + if !installed { fmt.Println("Not installed, installing...") err = pc.InstallPlugin(cmd.Context(), commandName, "", -1) @@ -98,7 +98,7 @@ func NewPluginCommand(commandName string, description string, aliases []string, fmt.Println("Installed successfully") } - pluginPath := path.Join(flags.DeckhousePluginsDir, "plugins", commandName) + pluginPath := path.Join(pc.pluginDirectory, "plugins", commandName) pluginBinaryPath := path.Join(pluginPath, "current") absPath, err := filepath.Abs(pluginBinaryPath) if err != nil { @@ -122,8 +122,8 @@ func NewPluginCommand(commandName string, description string, aliases []string, return systemCmd } -func checkInstalled(commandName string) (bool, error) { - installedFile := path.Join(flags.DeckhousePluginsDir, "plugins", commandName, "current") +func (pc *PluginsCommand) checkInstalled(commandName string) (bool, error) { + installedFile := path.Join(pc.pluginDirectory, "plugins", commandName, "current") absPath, err := filepath.Abs(installedFile) if err != nil { return false, fmt.Errorf("failed to compute absolute path: %w", err) diff --git a/cmd/plugins/plugins.go b/cmd/plugins/plugins.go index c971c32e..4c42ec4c 100644 --- a/cmd/plugins/plugins.go +++ b/cmd/plugins/plugins.go @@ -43,6 +43,7 @@ import ( type PluginsCommand struct { service *service.PluginService pluginRegistryClient registry.Client + pluginDirectory string logger *dkplog.Logger } @@ -63,7 +64,8 @@ type pluginsListData struct { func NewPluginsCommand(logger *dkplog.Logger) *PluginsCommand { return &PluginsCommand{ - logger: logger, + pluginDirectory: flags.DeckhousePluginsDir, + logger: logger, } } @@ -165,7 +167,7 @@ func (pc *PluginsCommand) preparePluginsListData(ctx context.Context, showInstal // fetchInstalledPlugins retrieves installed plugins from filesystem func (pc *PluginsCommand) fetchInstalledPlugins() ([]pluginDisplayInfo, error) { - plugins, err := os.ReadDir(path.Join(flags.DeckhousePluginsDir, "plugins")) + plugins, err := os.ReadDir(path.Join(pc.pluginDirectory, "plugins")) if err != nil { return nil, fmt.Errorf("failed to read plugins directory: %w", err) } @@ -173,7 +175,7 @@ func (pc *PluginsCommand) fetchInstalledPlugins() ([]pluginDisplayInfo, error) { res := make([]pluginDisplayInfo, 0, len(plugins)) for _, plugin := range plugins { - pluginBinaryPath := path.Join(flags.DeckhousePluginsDir, "plugins", plugin.Name(), "current") + pluginBinaryPath := path.Join(pc.pluginDirectory, "plugins", plugin.Name(), "current") cmd := exec.Command(pluginBinaryPath, "--version") output, err := cmd.Output() @@ -217,7 +219,7 @@ func (pc *PluginsCommand) fetchInstalledPlugins() ([]pluginDisplayInfo, error) { } func (pc *PluginsCommand) getInstalledPluginContract(pluginName string) (*internal.Plugin, error) { - contractFile := path.Join(flags.DeckhousePluginsDir, "cache", "contracts", pluginName+".json") + contractFile := path.Join(pc.pluginDirectory, "cache", "contracts", pluginName+".json") file, err := os.Open(contractFile) if err != nil { @@ -535,7 +537,7 @@ func (pc *PluginsCommand) InstallPlugin(ctx context.Context, pluginName, version func (pc *PluginsCommand) installPlugin(ctx context.Context, pluginName string, version *semver.Version, useMajor int) error { // create plugin directory if it doesn't exist // example path: /opt/deckhouse/lib/deckhouse-cli/plugins/example-plugin - pluginDir := path.Join(flags.DeckhousePluginsDir, "plugins", pluginName) + pluginDir := path.Join(pc.pluginDirectory, "plugins", pluginName) err := os.MkdirAll(pluginDir, 0755) if err != nil { return fmt.Errorf("failed to create plugin directory: %w", err) @@ -630,7 +632,7 @@ func (pc *PluginsCommand) installPlugin(ctx context.Context, pluginName string, // cache contract // example path: /opt/deckhouse/lib/deckhouse-cli/cache/contracts - contractDir := path.Join(flags.DeckhousePluginsDir, "cache", "contracts") + contractDir := path.Join(pc.pluginDirectory, "cache", "contracts") err = os.MkdirAll(contractDir, 0755) if err != nil { return fmt.Errorf("failed to create contract directory: %w", err) @@ -722,7 +724,7 @@ func (pc *PluginsCommand) pluginsUpdateAllCommand() *cobra.Command { fmt.Println("Updating all installed plugins...") - plugins, err := os.ReadDir(path.Join(flags.DeckhousePluginsDir, "plugins")) + plugins, err := os.ReadDir(path.Join(pc.pluginDirectory, "plugins")) if err != nil { return fmt.Errorf("failed to read plugins directory: %w", err) } @@ -754,7 +756,7 @@ func (pc *PluginsCommand) pluginsRemoveCommand() *cobra.Command { pluginName := args[0] fmt.Printf("Removing plugin: %s\n", pluginName) - pluginDir := path.Join(flags.DeckhousePluginsDir, "plugins", pluginName) + pluginDir := path.Join(pc.pluginDirectory, "plugins", pluginName) fmt.Printf("Removing plugin from: %s\n", pluginDir) err := os.RemoveAll(pluginDir) @@ -764,7 +766,7 @@ func (pc *PluginsCommand) pluginsRemoveCommand() *cobra.Command { fmt.Println("Cleaning up plugin files...") - os.Remove(path.Join(flags.DeckhousePluginsDir, "cache", "contracts", pluginName+".json")) + os.Remove(path.Join(pc.pluginDirectory, "cache", "contracts", pluginName+".json")) fmt.Printf("✓ Plugin '%s' successfully removed!\n", pluginName) @@ -786,7 +788,7 @@ func (pc *PluginsCommand) pluginsRemoveAllCommand() *cobra.Command { RunE: func(_ *cobra.Command, _ []string) error { fmt.Println("Removing all installed plugins...") - plugins, err := os.ReadDir(path.Join(flags.DeckhousePluginsDir, "plugins")) + plugins, err := os.ReadDir(path.Join(pc.pluginDirectory, "plugins")) if err != nil { return fmt.Errorf("failed to read plugins directory: %w", err) } @@ -794,7 +796,7 @@ func (pc *PluginsCommand) pluginsRemoveAllCommand() *cobra.Command { fmt.Println("Found", len(plugins), "plugins to remove:") for _, plugin := range plugins { - pluginDir := path.Join(flags.DeckhousePluginsDir, "plugins", plugin.Name()) + pluginDir := path.Join(pc.pluginDirectory, "plugins", plugin.Name()) fmt.Printf("Removing plugin from: %s\n", pluginDir) err := os.RemoveAll(pluginDir) @@ -804,7 +806,7 @@ func (pc *PluginsCommand) pluginsRemoveAllCommand() *cobra.Command { fmt.Printf("Cleaning up plugin files for '%s'...\n", plugin.Name()) - os.Remove(path.Join(flags.DeckhousePluginsDir, "cache", "contracts", plugin.Name()+".json")) + os.Remove(path.Join(pc.pluginDirectory, "cache", "contracts", plugin.Name()+".json")) fmt.Printf("✓ Plugin '%s' successfully removed!\n", plugin.Name()) } From 0ec3f988a0f88395f27dd1c00c90fccbf8f6b3de Mon Sep 17 00:00:00 2001 From: Smyslov Maxim Date: Fri, 26 Dec 2025 15:02:50 +0300 Subject: [PATCH 4/4] fix Signed-off-by: Smyslov Maxim --- cmd/plugins/plugins.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/plugins/plugins.go b/cmd/plugins/plugins.go index 4c42ec4c..2f44966e 100644 --- a/cmd/plugins/plugins.go +++ b/cmd/plugins/plugins.go @@ -85,13 +85,13 @@ func NewCommand(logger *dkplog.Logger) *cobra.Command { if errors.Is(err, os.ErrPermission) { pc.logger.Warn("use homedir instead of default d8 plugins path in '/opt/deckhouse/lib/deckhouse-cli'", slog.String("new_path", flags.DeckhousePluginsDir), dkplog.Err(err)) - flags.DeckhousePluginsDir, err = os.UserHomeDir() + newPluginDirectory, err := os.UserHomeDir() if err != nil { logger.Warn("failed to receive home dir to create plugins dir", slog.String("error", err.Error())) return } - flags.DeckhousePluginsDir = path.Join(flags.DeckhousePluginsDir, ".deckhouse-cli") + pc.pluginDirectory = path.Join(newPluginDirectory, ".deckhouse-cli") } }, }