diff --git a/pkg/catalog/cleanup.go b/pkg/catalog/cleanup.go index 16f013cb8..f4d5943ef 100644 --- a/pkg/catalog/cleanup.go +++ b/pkg/catalog/cleanup.go @@ -4,7 +4,6 @@ package catalog import ( - configlib "github.com/vmware-tanzu/tanzu-plugin-runtime/config" configtypes "github.com/vmware-tanzu/tanzu-plugin-runtime/config/types" ) @@ -47,27 +46,24 @@ func DeleteIncorrectPluginEntriesFromCatalog() { } // MigrateContextPluginsAsStandaloneIfNeeded updates the catalog cache to move all the -// context-scoped plugins associated with the active context as standalone plugins +// context-scoped plugins as standalone plugins // and removes the context-scoped plugin mapping from the catalog cache. -// This is to ensure backwards compatibility when user migrates from pre v1.3 version of -// the CLI, the context-scoped plugins are still gets shown as installed +// This is to ensure backwards compatibility when the user migrates from pre v1.3 version of +// the CLI, the context-scoped plugins are still shown as installed func MigrateContextPluginsAsStandaloneIfNeeded() { - activeContexts, err := configlib.GetAllActiveContextsList() - if err != nil || len(activeContexts) == 0 { - return - } - c, lockedFile, err := getCatalogCache(true) if err != nil { return } defer lockedFile.Close() - for _, ac := range activeContexts { - for pluginKey, installPath := range c.ServerPlugins[ac] { + for _, association := range c.ServerPlugins { + for pluginKey, installPath := range association { c.StandAlonePlugins.Add(pluginKey, installPath) } - delete(c.ServerPlugins, ac) } + // Delete all entries by reassigning to a new empty map + c.ServerPlugins = make(map[string]PluginAssociation) + _ = saveCatalogCache(c, lockedFile) } diff --git a/pkg/catalog/cleanup_test.go b/pkg/catalog/cleanup_test.go new file mode 100644 index 000000000..59e395dc3 --- /dev/null +++ b/pkg/catalog/cleanup_test.go @@ -0,0 +1,382 @@ +// Copyright 2024 VMware, Inc. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +package catalog + +import ( + "os" + "path/filepath" + "sort" + "testing" + + "github.com/otiai10/copy" + + "github.com/vmware-tanzu/tanzu-cli/pkg/cli" + "github.com/vmware-tanzu/tanzu-cli/pkg/common" + "github.com/vmware-tanzu/tanzu-cli/pkg/constants" + "github.com/vmware-tanzu/tanzu-plugin-runtime/config/types" + "github.com/vmware-tanzu/tanzu-plugin-runtime/plugin" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +func TestCatalogSuite(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "plugin catalog test suite") +} + +var _ = Describe("GetInstalledPlugins (standalone plugins)", func() { + var ( + cdir string + err error + configFile *os.File + configFileNG *os.File + pd1 *cli.PluginInfo + pd2 *cli.PluginInfo + pd3 *cli.PluginInfo + pd4 *cli.PluginInfo + pd5 *cli.PluginInfo + pd6 *cli.PluginInfo + originalVarValue string + ) + const ( + tmcContextName = "test-tmc-context" + k8sContextName = "test-mc" + ) + BeforeEach(func() { + cdir, err = os.MkdirTemp("", "test-catalog-cache") + Expect(err).ToNot(HaveOccurred()) + common.DefaultCacheDir = cdir + + configFile, err = os.CreateTemp("", "config") + Expect(err).To(BeNil()) + err = copy.Copy(filepath.Join("..", "fakes", "config", "tanzu_config.yaml"), configFile.Name()) + Expect(err).To(BeNil(), "Error while copying tanzu config file for testing") + os.Setenv("TANZU_CONFIG", configFile.Name()) + + configFileNG, err = os.CreateTemp("", "config_ng") + Expect(err).To(BeNil()) + os.Setenv("TANZU_CONFIG_NEXT_GEN", configFileNG.Name()) + err = copy.Copy(filepath.Join("..", "fakes", "config", "tanzu_config_ng.yaml"), configFileNG.Name()) + Expect(err).To(BeNil(), "Error while coping tanzu config-ng file for testing") + + originalVarValue = os.Getenv(constants.ConfigVariableStandaloneOverContextPlugins) + }) + AfterEach(func() { + os.RemoveAll(cdir) + os.Unsetenv("TANZU_CONFIG") + os.Unsetenv("TANZU_CONFIG_NEXT_GEN") + os.RemoveAll(configFile.Name()) + os.RemoveAll(configFileNG.Name()) + + os.Setenv(constants.ConfigVariableStandaloneOverContextPlugins, originalVarValue) + }) + + Context("when no standalone or server plugins installed", func() { + + It("should return empty plugin list", func() { + MigrateContextPluginsAsStandaloneIfNeeded() + + installedPlugins, err := getInstalledPlugins() + Expect(err).ToNot(HaveOccurred()) + Expect(len(installedPlugins)).To(Equal(0)) + }) + }) + Context("when a standalone plugins installed", func() { + BeforeEach(func() { + pd1, err = fakeInstallPlugin("", "fake-server-plugin1", types.TargetK8s, "v1.0.0") + Expect(err).ToNot(HaveOccurred()) + }) + + It("should return installed standalone plugin ", func() { + MigrateContextPluginsAsStandaloneIfNeeded() + + installedPlugins, err := getInstalledPlugins() + Expect(err).ToNot(HaveOccurred()) + Expect(len(installedPlugins)).To(Equal(1)) + Expect(installedPlugins).Should(ContainElement(*pd1)) + }) + + It("should return correct result for IsPluginInstalled", func() { + MigrateContextPluginsAsStandaloneIfNeeded() + + isInstalled := isPluginInstalled("fake-server-plugin1", types.TargetK8s, "v1.0.0") + Expect(isInstalled).To(BeTrue()) + isInstalled = isPluginInstalled("random-plugin", types.TargetK8s, "v1.0.0") + Expect(isInstalled).To(BeFalse()) + }) + }) + + Context("when a standalone and server plugin for k8s target installed", func() { + BeforeEach(func() { + pd1, err = fakeInstallPlugin("", "fake-server-plugin1", types.TargetK8s, "v1.0.0") + Expect(err).ToNot(HaveOccurred()) + + contextNameFromConfig := k8sContextName + pd2, err = fakeInstallPlugin(contextNameFromConfig, "fake-server-plugin2", types.TargetK8s, "v1.0.0") + Expect(err).ToNot(HaveOccurred()) + }) + + It("should return installed plugins ", func() { + MigrateContextPluginsAsStandaloneIfNeeded() + + installedPlugins, err := getInstalledPlugins() + Expect(err).ToNot(HaveOccurred()) + Expect(len(installedPlugins)).To(Equal(2)) // server plugins will be migrated as standalone + Expect(installedPlugins).Should(ContainElement(*pd1)) + Expect(installedPlugins).Should(ContainElement(*pd2)) + }) + }) + + Context("when a standalone plugin and server plugin for both tmc and k8s targets installed", func() { + BeforeEach(func() { + pd1, err = fakeInstallPlugin("", "fake-server-plugin1", types.TargetK8s, "v1.0.0") + Expect(err).ToNot(HaveOccurred()) + + contextNameFromConfig := k8sContextName + pd2, err = fakeInstallPlugin(contextNameFromConfig, "fake-server-plugin2", types.TargetK8s, "v1.0.0") + Expect(err).ToNot(HaveOccurred()) + + contextNameFromConfig = tmcContextName + pd3, err = fakeInstallPlugin(contextNameFromConfig, "fake-server-plugin3", types.TargetTMC, "v1.0.0") + Expect(err).ToNot(HaveOccurred()) + }) + + It("should return installed plugins ", func() { + MigrateContextPluginsAsStandaloneIfNeeded() + + installedPlugins, err := getInstalledPlugins() + Expect(err).ToNot(HaveOccurred()) + Expect(len(installedPlugins)).To(Equal(3)) // server plugins will be migrated as standalone + Expect(installedPlugins).Should(ContainElement(*pd1)) + Expect(installedPlugins).Should(ContainElement(*pd2)) + Expect(installedPlugins).Should(ContainElement(*pd3)) + }) + }) + + Context("when a standalone plugin and server plugin of the same name and target are installed", func() { + BeforeEach(func() { + sharedPluginName := "fake-plugin" + sharedPluginTarget := types.TargetK8s + pd1, err = fakeInstallPlugin("", sharedPluginName, sharedPluginTarget, "v1.0.0") + Expect(err).ToNot(HaveOccurred()) + + contextNameFromConfig := k8sContextName + pd2, err = fakeInstallPlugin(contextNameFromConfig, sharedPluginName, sharedPluginTarget, "v2.0.0") + Expect(err).ToNot(HaveOccurred()) + }) + + It("should return the server plugin only", func() { + MigrateContextPluginsAsStandaloneIfNeeded() + + installedPlugins, err := getInstalledPlugins() + Expect(err).ToNot(HaveOccurred()) + Expect(len(installedPlugins)).To(Equal(1)) + Expect(installedPlugins).Should(ContainElement(*pd2)) + }) + }) + + Context("when multiple standalone plugins and server plugins are installed with some overlap", func() { + BeforeEach(func() { + pd1, err = fakeInstallPlugin("", "fake-server-plugin1", types.TargetK8s, "v1.0.0") + Expect(err).ToNot(HaveOccurred()) + + contextNameFromConfig := k8sContextName + pd2, err = fakeInstallPlugin(contextNameFromConfig, "fake-server-plugin2", types.TargetK8s, "v1.0.0") + Expect(err).ToNot(HaveOccurred()) + + sharedPluginName := "fake-plugin1" + sharedPluginTarget := types.TargetK8s + pd3, err = fakeInstallPlugin("", sharedPluginName, sharedPluginTarget, "v1.0.0") + Expect(err).ToNot(HaveOccurred()) + pd4, err = fakeInstallPlugin(contextNameFromConfig, sharedPluginName, sharedPluginTarget, "v2.0.0") + Expect(err).ToNot(HaveOccurred()) + + sharedPluginName = "fake-plugin2" + sharedPluginTarget = types.TargetTMC + pd5, err = fakeInstallPlugin("", sharedPluginName, sharedPluginTarget, "v1.0.0") + Expect(err).ToNot(HaveOccurred()) + pd6, err = fakeInstallPlugin(contextNameFromConfig, sharedPluginName, sharedPluginTarget, "v2.0.0") + Expect(err).ToNot(HaveOccurred()) + }) + + It("should not return any server plugins and only standalone plugins should be listed", func() { + MigrateContextPluginsAsStandaloneIfNeeded() + + installedPlugins, err := getInstalledPlugins() + Expect(err).ToNot(HaveOccurred()) + Expect(len(installedPlugins)).To(Equal(4)) + Expect(installedPlugins).Should(ContainElement(*pd1)) + Expect(installedPlugins).Should(ContainElement(*pd2)) + Expect(installedPlugins).ShouldNot(ContainElement(*pd3)) + Expect(installedPlugins).Should(ContainElement(*pd4)) + Expect(installedPlugins).ShouldNot(ContainElement(*pd5)) + Expect(installedPlugins).Should(ContainElement(*pd6)) + }) + }) + + Context("with a catalog cache from an older CLI version", func() { + BeforeEach(func() { + cdir, err = os.MkdirTemp("", "test-catalog-cache") + Expect(err).ToNot(HaveOccurred()) + common.DefaultCacheDir = cdir + + err = copy.Copy( + filepath.Join("..", "fakes", "cache", "catalog_v0.29.yaml"), + // filepath.Join("..", "fakes", "cache", "catalog.yaml"), + filepath.Join(common.DefaultCacheDir, "catalog.yaml")) + Expect(err).To(BeNil(), "Error while copying tanzu catalog file for testing") + + configFile, err = os.CreateTemp("", "config") + Expect(err).To(BeNil()) + err = copy.Copy(filepath.Join("..", "fakes", "config", "tanzu_config.yaml"), configFile.Name()) + Expect(err).To(BeNil(), "Error while copying tanzu config file for testing") + os.Setenv("TANZU_CONFIG", configFile.Name()) + + configFileNG, err = os.CreateTemp("", "config_ng") + Expect(err).To(BeNil()) + os.Setenv("TANZU_CONFIG_NEXT_GEN", configFileNG.Name()) + err = copy.Copy(filepath.Join("..", "fakes", "config", "tanzu_config_ng.yaml"), configFileNG.Name()) + Expect(err).To(BeNil(), "Error while coping tanzu config-ng file for testing") + }) + AfterEach(func() { + os.RemoveAll(cdir) + os.Unsetenv("TANZU_CONFIG") + os.Unsetenv("TANZU_CONFIG_NEXT_GEN") + os.RemoveAll(configFile.Name()) + os.RemoveAll(configFileNG.Name()) + }) + + It("should find the installed standalone plugin along with server plugins with server plugins migrated in catalog", func() { + MigrateContextPluginsAsStandaloneIfNeeded() + + installedStandalonePlugins, err := getInstalledPlugins() + Expect(err).ToNot(HaveOccurred()) + sort.Sort(cli.PluginInfoSorter(installedStandalonePlugins)) + Expect(len(installedStandalonePlugins)).To(Equal(3)) + Expect(installedStandalonePlugins[0]).Should(Equal( + cli.PluginInfo{ + Name: "cluster", + Description: "cluster functionality", + Version: "v0.0.1", + BuildSHA: "01234567", + Digest: "", + Group: plugin.SystemCmdGroup, + DocURL: "", + Hidden: false, + CompletionType: 0, + CompletionArgs: nil, + CompletionCommand: "", + Aliases: nil, + InstallationPath: "/Users/test/Library/Application Support/tanzu-cli/cluster/v0.0.1_2ddee7c0a8ecbef610a651bc8d83657fd3438f1038e817b4a7d44f2d0b3bac72_kubernetes", + Discovery: "test-mc", + Scope: "", + Status: "", + DiscoveredRecommendedVersion: "v0.0.1", + Target: types.TargetK8s, + PostInstallHook: nil, + DefaultFeatureFlags: map[string]bool{}, + InvokedAs: nil, + SupportedContextType: nil, + }, + )) + Expect(installedStandalonePlugins[1]).Should(Equal( + cli.PluginInfo{ + Name: "iam", + Description: "IAM Policies for tmc resources", + Version: "v0.0.1", + BuildSHA: "01234567", + Digest: "", + Group: plugin.ManageCmdGroup, + DocURL: "", + Hidden: false, + CompletionType: 0, + CompletionArgs: nil, + CompletionCommand: "", + Aliases: nil, + InstallationPath: "/Users/test/Library/Application Support/tanzu-cli/iam/v0.0.1_2de17ef20dfb00dd8bcf5cb61cbce3cbddcd0a71fba858817343188c093cef7c_mission-control", + Discovery: "test-tmc-context", + Scope: "", + Status: "", + DiscoveredRecommendedVersion: "v0.0.1", + Target: types.TargetTMC, + PostInstallHook: nil, + DefaultFeatureFlags: map[string]bool{}, + InvokedAs: nil, + SupportedContextType: nil, + }, + )) + Expect(installedStandalonePlugins[2]).Should(Equal( + cli.PluginInfo{ + Name: "isolated-cluster", + Description: "Prepopulating images/bundle for internet-restricted environments", + Version: "v0.29.0", + BuildSHA: "e403941f7", + Digest: "", + Group: plugin.RunCmdGroup, + DocURL: "", + Hidden: false, + CompletionType: 0, + CompletionArgs: nil, + CompletionCommand: "", + Aliases: nil, + InstallationPath: "/Users/test/Library/Application Support/tanzu-cli/isolated-cluster/v0.29.0_78d8b432ca369a161fca39e777aeb81fe63c2ba8b8dd25b1b8270eeab485a2ca_", + Discovery: "", + Scope: "", + Status: "", + DiscoveredRecommendedVersion: "v0.29.0", + Target: types.TargetUnknown, + DefaultFeatureFlags: map[string]bool{}, + PostInstallHook: nil, + }, + )) + }) + }) +}) + +func fakeInstallPlugin(contextName, pluginName string, target types.Target, version string) (*cli.PluginInfo, error) { + cc, err := NewContextCatalogUpdater(contextName) + if err != nil { + return nil, err + } + defer cc.Unlock() + pi := &cli.PluginInfo{ + Name: pluginName, + InstallationPath: "/path/to/plugin/" + pluginName + "/" + version, + Version: version, + Hidden: true, + Target: target, + DefaultFeatureFlags: map[string]bool{ + "test-feature": true, + }, + } + err = cc.Upsert(pi) + if err != nil { + return nil, err + } + return pi, nil +} + +func getInstalledPlugins() ([]cli.PluginInfo, error) { + // Get all the standalone plugins found in the catalog + standAloneCatalog, err := NewContextCatalog("") + if err != nil { + return nil, err + } + return standAloneCatalog.List(), nil +} + +func isPluginInstalled(name string, target types.Target, version string) bool { + // Check if the plugin is already installed, if installed skip the installation of the plugin + installedPlugins, err := getInstalledPlugins() + if err == nil { + for i := range installedPlugins { + if installedPlugins[i].Name == name && + installedPlugins[i].Target == target && + installedPlugins[i].Version == version { + return true + } + } + } + return false +} diff --git a/pkg/globalinit/catalog_cache_init.go b/pkg/globalinit/catalog_cache_init.go index 5e4a9e45a..124ba1778 100644 --- a/pkg/globalinit/catalog_cache_init.go +++ b/pkg/globalinit/catalog_cache_init.go @@ -20,10 +20,12 @@ import ( ) // This global initializer checks if the last executed CLI version is < 1.3.0. -// If so it refreshes the plugin catalog to make sure any remapping data is in the catalog. +// If so it refreshes the plugin catalog to: +// 1- migrate context-scoped plugins as standalone plugins +// 2- make sure any remapping data is in the catalog func init() { - RegisterInitializer("Plugin Info Catalog Initializer", triggerForPreCommandRemapping, refreshPluginCatalog) + RegisterInitializer("Plugin Info Catalog Initializer", triggerForPreCommandRemapping, updatePluginCatalog) } func triggerForPreCommandRemapping() bool { @@ -31,10 +33,22 @@ func triggerForPreCommandRemapping() bool { return lastversion.GetLastExecutedCLIVersion() == lastversion.OlderThan1_3_0 } -// refreshPluginCatalog reads the info from each installed plugin +// updatePluginCatalog does the following catalog udpates: +// 1- Migrate context-scoped plugins as standalone plugins +// 2- Reads the info from each installed plugin and updates the plugin catalog +// +// with the latest info. We need to do this to make sure the command re-mapping +// data is in the cache. +func updatePluginCatalog(outStream io.Writer) error { + catalog.MigrateContextPluginsAsStandaloneIfNeeded() + + return refreshPluginsForRemapping(outStream) +} + +// refreshPluginsForRemapping reads the info from each installed plugin // and updates the plugin catalog with the latest info. // We need to do this to make sure the command re-mapping data is in the cache. -func refreshPluginCatalog(outStream io.Writer) error { +func refreshPluginsForRemapping(outStream io.Writer) error { plugins, err := pluginsupplier.GetInstalledPlugins() if err != nil { return err diff --git a/pkg/pluginsupplier/plugin_supplier.go b/pkg/pluginsupplier/plugin_supplier.go index ac5881115..10b6e3427 100644 --- a/pkg/pluginsupplier/plugin_supplier.go +++ b/pkg/pluginsupplier/plugin_supplier.go @@ -15,11 +15,6 @@ import ( // GetInstalledPlugins return the installed plugins func GetInstalledPlugins() ([]cli.PluginInfo, error) { - // Migrate context-scoped plugins as standalone plugin if required - // TODO(anujc): Think on how to invoke this function just once after the newer version - // of the CLI gets installed as we just need to do this migration once - catalog.MigrateContextPluginsAsStandaloneIfNeeded() - // Get all the standalone plugins found in the catalog standAloneCatalog, err := catalog.NewContextCatalog("") if err != nil { diff --git a/pkg/pluginsupplier/plugin_supplier_test.go b/pkg/pluginsupplier/plugin_supplier_test.go index cc10c4507..9575e658b 100644 --- a/pkg/pluginsupplier/plugin_supplier_test.go +++ b/pkg/pluginsupplier/plugin_supplier_test.go @@ -5,7 +5,6 @@ package pluginsupplier import ( "os" "path/filepath" - "sort" "testing" "github.com/otiai10/copy" @@ -15,7 +14,6 @@ import ( "github.com/vmware-tanzu/tanzu-cli/pkg/common" "github.com/vmware-tanzu/tanzu-cli/pkg/constants" "github.com/vmware-tanzu/tanzu-plugin-runtime/config/types" - "github.com/vmware-tanzu/tanzu-plugin-runtime/plugin" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" @@ -73,17 +71,8 @@ var _ = Describe("GetInstalledPlugins (standalone plugins)", func() { configFile *os.File configFileNG *os.File pd1 *cli.PluginInfo - pd2 *cli.PluginInfo - pd3 *cli.PluginInfo - pd4 *cli.PluginInfo - pd5 *cli.PluginInfo - pd6 *cli.PluginInfo originalVarValue string ) - const ( - tmcContextName = "test-tmc-context" - k8sContextName = "test-mc" - ) BeforeEach(func() { cdir, err = os.MkdirTemp("", "test-catalog-cache") Expect(err).ToNot(HaveOccurred()) @@ -141,222 +130,6 @@ var _ = Describe("GetInstalledPlugins (standalone plugins)", func() { Expect(isInstalled).To(BeFalse()) }) }) - - Context("when a standalone and server plugin for k8s target installed", func() { - BeforeEach(func() { - pd1, err = fakeInstallPlugin("", "fake-server-plugin1", types.TargetK8s, "v1.0.0") - Expect(err).ToNot(HaveOccurred()) - - contextNameFromConfig := k8sContextName - pd2, err = fakeInstallPlugin(contextNameFromConfig, "fake-server-plugin2", types.TargetK8s, "v1.0.0") - Expect(err).ToNot(HaveOccurred()) - }) - - It("should return installed plugins ", func() { - installedPlugins, err := GetInstalledPlugins() - Expect(err).ToNot(HaveOccurred()) - Expect(len(installedPlugins)).To(Equal(2)) // server plugins will be migrated as standalone - Expect(installedPlugins).Should(ContainElement(*pd1)) - Expect(installedPlugins).Should(ContainElement(*pd2)) - }) - }) - - Context("when a standalone plugin and server plugin for both tmc and k8s targets installed", func() { - BeforeEach(func() { - pd1, err = fakeInstallPlugin("", "fake-server-plugin1", types.TargetK8s, "v1.0.0") - Expect(err).ToNot(HaveOccurred()) - - contextNameFromConfig := k8sContextName - pd2, err = fakeInstallPlugin(contextNameFromConfig, "fake-server-plugin2", types.TargetK8s, "v1.0.0") - Expect(err).ToNot(HaveOccurred()) - - contextNameFromConfig = tmcContextName - pd3, err = fakeInstallPlugin(contextNameFromConfig, "fake-server-plugin3", types.TargetTMC, "v1.0.0") - Expect(err).ToNot(HaveOccurred()) - }) - - It("should return installed plugins ", func() { - installedPlugins, err := GetInstalledPlugins() - Expect(err).ToNot(HaveOccurred()) - Expect(len(installedPlugins)).To(Equal(3)) // server plugins will be migrated as standalone - Expect(installedPlugins).Should(ContainElement(*pd1)) - Expect(installedPlugins).Should(ContainElement(*pd2)) - Expect(installedPlugins).Should(ContainElement(*pd3)) - }) - }) - - Context("when a standalone plugin and server plugin of the same name and target are installed", func() { - BeforeEach(func() { - sharedPluginName := "fake-plugin" - sharedPluginTarget := types.TargetK8s - pd1, err = fakeInstallPlugin("", sharedPluginName, sharedPluginTarget, "v1.0.0") - Expect(err).ToNot(HaveOccurred()) - - contextNameFromConfig := k8sContextName - pd2, err = fakeInstallPlugin(contextNameFromConfig, sharedPluginName, sharedPluginTarget, "v2.0.0") - Expect(err).ToNot(HaveOccurred()) - }) - - It("should return the server plugin only", func() { - installedPlugins, err := GetInstalledPlugins() - Expect(err).ToNot(HaveOccurred()) - Expect(len(installedPlugins)).To(Equal(1)) - Expect(installedPlugins).Should(ContainElement(*pd2)) - }) - }) - - Context("when multiple standalone plugins and server plugins are installed with some overlap", func() { - BeforeEach(func() { - pd1, err = fakeInstallPlugin("", "fake-server-plugin1", types.TargetK8s, "v1.0.0") - Expect(err).ToNot(HaveOccurred()) - - contextNameFromConfig := k8sContextName - pd2, err = fakeInstallPlugin(contextNameFromConfig, "fake-server-plugin2", types.TargetK8s, "v1.0.0") - Expect(err).ToNot(HaveOccurred()) - - sharedPluginName := "fake-plugin1" - sharedPluginTarget := types.TargetK8s - pd3, err = fakeInstallPlugin("", sharedPluginName, sharedPluginTarget, "v1.0.0") - Expect(err).ToNot(HaveOccurred()) - pd4, err = fakeInstallPlugin(contextNameFromConfig, sharedPluginName, sharedPluginTarget, "v2.0.0") - Expect(err).ToNot(HaveOccurred()) - - sharedPluginName = "fake-plugin2" - sharedPluginTarget = types.TargetTMC - pd5, err = fakeInstallPlugin("", sharedPluginName, sharedPluginTarget, "v1.0.0") - Expect(err).ToNot(HaveOccurred()) - pd6, err = fakeInstallPlugin(contextNameFromConfig, sharedPluginName, sharedPluginTarget, "v2.0.0") - Expect(err).ToNot(HaveOccurred()) - }) - - It("should not return any server plugins and only standalone plugins should be listed", func() { - installedPlugins, err := GetInstalledPlugins() - Expect(err).ToNot(HaveOccurred()) - Expect(len(installedPlugins)).To(Equal(4)) - Expect(installedPlugins).Should(ContainElement(*pd1)) - Expect(installedPlugins).Should(ContainElement(*pd2)) - Expect(installedPlugins).ShouldNot(ContainElement(*pd3)) - Expect(installedPlugins).Should(ContainElement(*pd4)) - Expect(installedPlugins).ShouldNot(ContainElement(*pd5)) - Expect(installedPlugins).Should(ContainElement(*pd6)) - }) - }) - - Context("with a catalog cache from an older CLI version", func() { - BeforeEach(func() { - cdir, err = os.MkdirTemp("", "test-catalog-cache") - Expect(err).ToNot(HaveOccurred()) - common.DefaultCacheDir = cdir - - err = copy.Copy( - filepath.Join("..", "fakes", "cache", "catalog_v0.29.yaml"), - // filepath.Join("..", "fakes", "cache", "catalog.yaml"), - filepath.Join(common.DefaultCacheDir, "catalog.yaml")) - Expect(err).To(BeNil(), "Error while copying tanzu catalog file for testing") - - configFile, err = os.CreateTemp("", "config") - Expect(err).To(BeNil()) - err = copy.Copy(filepath.Join("..", "fakes", "config", "tanzu_config.yaml"), configFile.Name()) - Expect(err).To(BeNil(), "Error while copying tanzu config file for testing") - os.Setenv("TANZU_CONFIG", configFile.Name()) - - configFileNG, err = os.CreateTemp("", "config_ng") - Expect(err).To(BeNil()) - os.Setenv("TANZU_CONFIG_NEXT_GEN", configFileNG.Name()) - err = copy.Copy(filepath.Join("..", "fakes", "config", "tanzu_config_ng.yaml"), configFileNG.Name()) - Expect(err).To(BeNil(), "Error while coping tanzu config-ng file for testing") - }) - AfterEach(func() { - os.RemoveAll(cdir) - os.Unsetenv("TANZU_CONFIG") - os.Unsetenv("TANZU_CONFIG_NEXT_GEN") - os.RemoveAll(configFile.Name()) - os.RemoveAll(configFileNG.Name()) - }) - - It("should find the installed standalone plugin along with server plugins with server plugins migrated in catalog", func() { - installedStandalonePlugins, err := GetInstalledPlugins() - Expect(err).ToNot(HaveOccurred()) - sort.Sort(cli.PluginInfoSorter(installedStandalonePlugins)) - Expect(len(installedStandalonePlugins)).To(Equal(3)) - Expect(installedStandalonePlugins[0]).Should(Equal( - cli.PluginInfo{ - Name: "cluster", - Description: "cluster functionality", - Version: "v0.0.1", - BuildSHA: "01234567", - Digest: "", - Group: plugin.SystemCmdGroup, - DocURL: "", - Hidden: false, - CompletionType: 0, - CompletionArgs: nil, - CompletionCommand: "", - Aliases: nil, - InstallationPath: "/Users/test/Library/Application Support/tanzu-cli/cluster/v0.0.1_2ddee7c0a8ecbef610a651bc8d83657fd3438f1038e817b4a7d44f2d0b3bac72_kubernetes", - Discovery: "test-mc", - Scope: "", - Status: "", - DiscoveredRecommendedVersion: "v0.0.1", - Target: types.TargetK8s, - PostInstallHook: nil, - DefaultFeatureFlags: map[string]bool{}, - InvokedAs: nil, - SupportedContextType: nil, - }, - )) - Expect(installedStandalonePlugins[1]).Should(Equal( - cli.PluginInfo{ - Name: "iam", - Description: "IAM Policies for tmc resources", - Version: "v0.0.1", - BuildSHA: "01234567", - Digest: "", - Group: plugin.ManageCmdGroup, - DocURL: "", - Hidden: false, - CompletionType: 0, - CompletionArgs: nil, - CompletionCommand: "", - Aliases: nil, - InstallationPath: "/Users/test/Library/Application Support/tanzu-cli/iam/v0.0.1_2de17ef20dfb00dd8bcf5cb61cbce3cbddcd0a71fba858817343188c093cef7c_mission-control", - Discovery: "test-tmc-context", - Scope: "", - Status: "", - DiscoveredRecommendedVersion: "v0.0.1", - Target: types.TargetTMC, - PostInstallHook: nil, - DefaultFeatureFlags: map[string]bool{}, - InvokedAs: nil, - SupportedContextType: nil, - }, - )) - Expect(installedStandalonePlugins[2]).Should(Equal( - cli.PluginInfo{ - Name: "isolated-cluster", - Description: "Prepopulating images/bundle for internet-restricted environments", - Version: "v0.29.0", - BuildSHA: "e403941f7", - Digest: "", - Group: plugin.RunCmdGroup, - DocURL: "", - Hidden: false, - CompletionType: 0, - CompletionArgs: nil, - CompletionCommand: "", - Aliases: nil, - InstallationPath: "/Users/test/Library/Application Support/tanzu-cli/isolated-cluster/v0.29.0_78d8b432ca369a161fca39e777aeb81fe63c2ba8b8dd25b1b8270eeab485a2ca_", - Discovery: "", - Scope: "", - Status: "", - DiscoveredRecommendedVersion: "v0.29.0", - Target: types.TargetUnknown, - DefaultFeatureFlags: map[string]bool{}, - PostInstallHook: nil, - }, - )) - }) - }) }) func fakeInstallPlugin(contextName, pluginName string, target types.Target, version string) (*cli.PluginInfo, error) {