diff --git a/go.mod b/go.mod index ddc06ab86..e4799e902 100644 --- a/go.mod +++ b/go.mod @@ -43,7 +43,6 @@ require ( github.com/vmware-tanzu/tanzu-framework/capabilities/client v0.0.0-20230523145612-1c6fbba34686 github.com/vmware-tanzu/tanzu-plugin-runtime v1.0.0 go.pinniped.dev v0.20.0 - go.uber.org/multierr v1.11.0 golang.org/x/mod v0.10.0 golang.org/x/oauth2 v0.8.0 golang.org/x/sync v0.2.0 @@ -212,6 +211,7 @@ require ( go.opentelemetry.io/otel v1.15.0 // indirect go.opentelemetry.io/otel/trace v1.15.0 // indirect go.uber.org/atomic v1.10.0 // indirect + go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.24.0 // indirect golang.org/x/crypto v0.9.0 // indirect golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect diff --git a/pkg/constants/featureflags.go b/pkg/constants/featureflags.go index b7a9951fb..d1fa7d5b5 100644 --- a/pkg/constants/featureflags.go +++ b/pkg/constants/featureflags.go @@ -7,8 +7,6 @@ package constants const ( // FeatureContextCommand determines whether to surface the context command. This is disabled by default. FeatureContextCommand = "features.global.context-target-v2" - // FeatureDisableCentralRepositoryForTesting determines if the CLI uses the Central Repository of plugins. - FeatureDisableCentralRepositoryForTesting = "features.global.no-central-repo-test-only" ) // DefaultCliFeatureFlags is used to populate an initially empty config file with default values for feature flags. diff --git a/pkg/discovery/oci.go b/pkg/discovery/oci.go index 286f20b21..7eabd600c 100644 --- a/pkg/discovery/oci.go +++ b/pkg/discovery/oci.go @@ -4,8 +4,10 @@ package discovery import ( + "os" "path" "path/filepath" + "strconv" "github.com/vmware-tanzu/tanzu-cli/pkg/common" "github.com/vmware-tanzu/tanzu-cli/pkg/plugininventory" @@ -22,6 +24,10 @@ func NewOCIDiscovery(name, image string, options ...DiscoveryOptions) Discovery discovery := newDBBackedOCIDiscovery(name, image) discovery.pluginCriteria = opts.PluginDiscoveryCriteria discovery.useLocalCacheOnly = opts.UseLocalCacheOnly + // NOTE: the use of TEST_TANZU_CLI_USE_DB_CACHE_ONLY is for testing only + if useCacheOnlyForTesting, _ := strconv.ParseBool(os.Getenv("TEST_TANZU_CLI_USE_DB_CACHE_ONLY")); useCacheOnlyForTesting { + discovery.useLocalCacheOnly = true + } return discovery } @@ -36,6 +42,10 @@ func NewOCIGroupDiscovery(name, image string, options ...DiscoveryOptions) Group discovery := newDBBackedOCIDiscovery(name, image) discovery.groupCriteria = opts.GroupDiscoveryCriteria discovery.useLocalCacheOnly = opts.UseLocalCacheOnly + // NOTE: the use of TEST_TANZU_CLI_USE_DB_CACHE_ONLY is for testing only + if useCacheOnlyForTesting, _ := strconv.ParseBool(os.Getenv("TEST_TANZU_CLI_USE_DB_CACHE_ONLY")); useCacheOnlyForTesting { + discovery.useLocalCacheOnly = true + } return discovery } diff --git a/pkg/pluginmanager/manager.go b/pkg/pluginmanager/manager.go index e7da64ace..319d08b43 100644 --- a/pkg/pluginmanager/manager.go +++ b/pkg/pluginmanager/manager.go @@ -15,8 +15,6 @@ import ( "strings" "github.com/pkg/errors" - "go.uber.org/multierr" - "golang.org/x/mod/semver" "gopkg.in/yaml.v2" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" kerrors "k8s.io/apimachinery/pkg/util/errors" @@ -31,7 +29,6 @@ import ( "github.com/vmware-tanzu/tanzu-cli/pkg/cli" "github.com/vmware-tanzu/tanzu-cli/pkg/common" "github.com/vmware-tanzu/tanzu-cli/pkg/config" - "github.com/vmware-tanzu/tanzu-cli/pkg/constants" "github.com/vmware-tanzu/tanzu-cli/pkg/discovery" "github.com/vmware-tanzu/tanzu-cli/pkg/distribution" "github.com/vmware-tanzu/tanzu-cli/pkg/plugincmdtree" @@ -65,34 +62,6 @@ type DeletePluginOptions struct { ForceDelete bool } -// ValidatePlugin validates the plugin info. -func ValidatePlugin(p *cli.PluginInfo) (err error) { - // skip builder plugin for bootstrapping - if p.Name == "builder" { - return nil - } - if p.Name == "" { - err = multierr.Append(err, errors.New("plugin name cannot be empty")) - } - if p.Version == "" { - err = multierr.Append(err, fmt.Errorf("plugin %q version cannot be empty", p.Name)) - } - if !semver.IsValid(p.Version) && p.Version != "dev" { - err = multierr.Append(err, fmt.Errorf("version %q %q is not a valid semantic version", p.Name, p.Version)) - } - if p.Description == "" { - err = multierr.Append(err, fmt.Errorf("plugin %q description cannot be empty", p.Name)) - } - if p.Group == "" { - err = multierr.Append(err, fmt.Errorf("plugin %q group cannot be empty", p.Name)) - } - return -} - -func discoverPlugins(pd []configtypes.PluginDiscovery) ([]discovery.Discovered, error) { - return discoverSpecificPlugins(pd, nil) -} - // discoverSpecificPlugins returns all plugins that match the specified criteria from all PluginDiscovery sources, // along with an aggregated error (if any) that occurred while creating the plugin discovery source or fetching plugins. func discoverSpecificPlugins(pd []configtypes.PluginDiscovery, options ...discovery.DiscoveryOptions) ([]discovery.Discovered, error) { @@ -194,15 +163,6 @@ func GetAdditionalTestPluginDiscoveries() []configtypes.PluginDiscovery { // DiscoverServerPlugins returns the available plugins associated all the active contexts func DiscoverServerPlugins() ([]discovery.Discovered, error) { - // If the context and target feature is enabled, discover plugins from all currentContexts - // Else discover plugin based on current Server - if configlib.IsFeatureActivated(constants.FeatureContextCommand) { - return discoverServerPluginsBasedOnAllCurrentContexts() - } - return discoverServerPluginsBasedOnCurrentServer() -} - -func discoverServerPluginsBasedOnAllCurrentContexts() ([]discovery.Discovered, error) { var plugins []discovery.Discovered var errList []error @@ -218,7 +178,7 @@ func discoverServerPluginsBasedOnAllCurrentContexts() ([]discovery.Discovered, e var discoverySources []configtypes.PluginDiscovery discoverySources = append(discoverySources, context.DiscoverySources...) discoverySources = append(discoverySources, defaultDiscoverySourceBasedOnContext(context)...) - discoveredPlugins, err := discoverPlugins(discoverySources) + discoveredPlugins, err := discoverSpecificPlugins(discoverySources) // If there is an error while discovering plugins from all of the given plugin sources, // append the error to the error list and continue processing the discoveredPlugins, @@ -244,144 +204,6 @@ func discoverServerPluginsBasedOnAllCurrentContexts() ([]discovery.Discovered, e return plugins, kerrors.NewAggregate(errList) } -// discoverServerPluginsBasedOnCurrentServer returns the available plugins associated with the given server -func discoverServerPluginsBasedOnCurrentServer() ([]discovery.Discovered, error) { - var plugins []discovery.Discovered - - server, err := configlib.GetCurrentServer() // nolint:staticcheck // Deprecated - if err != nil || server == nil { - // If servername is not specified than returning empty list - // as there are no server plugins that can be discovered - return plugins, nil - } - var discoverySources []configtypes.PluginDiscovery - discoverySources = append(discoverySources, server.DiscoverySources...) - discoverySources = append(discoverySources, defaultDiscoverySourceBasedOnServer(server)...) - - plugins, err = discoverPlugins(discoverySources) - if err != nil { - log.Warningf(errorWhileDiscoveringPlugins, err.Error()) - } - for i := range plugins { - plugins[i].Scope = common.PluginScopeContext - plugins[i].Status = common.PluginStatusNotInstalled - } - return plugins, nil -} - -// DiscoverPlugins returns all the discovered plugins including standalone and context-scoped plugins -// Context scoped plugin discovery happens for all active contexts -func DiscoverPlugins() ([]discovery.Discovered, []discovery.Discovered) { - serverPlugins, err := DiscoverServerPlugins() - if err != nil { - log.Warningf("unable to discover server plugins, %v", err.Error()) - } - - standalonePlugins, err := DiscoverStandalonePlugins(nil) - if err != nil { - log.Warningf("unable to discover standalone plugins, %v", err.Error()) - } - - // TODO(anuj): Remove duplicate plugins with server plugins getting higher priority - return serverPlugins, standalonePlugins -} - -// AvailablePlugins returns the list of available plugins including discovered and installed plugins. -// Plugin discovery happens for all active contexts -func AvailablePlugins() ([]discovery.Discovered, error) { - discoveredServerPlugins, discoveredStandalonePlugins := DiscoverPlugins() - return availablePlugins(discoveredServerPlugins, discoveredStandalonePlugins) -} - -// AvailablePluginsFromLocalSource returns the list of available plugins from local source -func AvailablePluginsFromLocalSource(localPath string) ([]discovery.Discovered, error) { - localStandalonePlugins, err := DiscoverPluginsFromLocalSource(localPath) - if err != nil { - log.Warningf("Unable to discover standalone plugins from local source, %v", err.Error()) - } - return availablePlugins([]discovery.Discovered{}, localStandalonePlugins) -} - -func availablePlugins(discoveredServerPlugins, discoveredStandalonePlugins []discovery.Discovered) ([]discovery.Discovered, error) { - installedPlugins, err := pluginsupplier.GetInstalledPlugins() - if err != nil { - return nil, err - } - - availablePlugins := availablePluginsFromStandaloneAndServerPlugins(discoveredServerPlugins, discoveredStandalonePlugins) - setAvailablePluginsStatus(availablePlugins, installedPlugins) - - installedStandalonePlugins, err := pluginsupplier.GetInstalledStandalonePlugins() - if err != nil { - return nil, err - } - installedButNotDiscoveredPlugins := getInstalledButNotDiscoveredStandalonePlugins(availablePlugins, installedStandalonePlugins) - availablePlugins = append(availablePlugins, installedButNotDiscoveredPlugins...) - - availablePlugins = combineDuplicatePlugins(availablePlugins) - - return availablePlugins, nil -} - -// combineDuplicatePlugins combines same plugins to eliminate duplicates -// When there is a plugin name conflicts and target of both the plugins are same, remove duplicate one. -// In addition to above, plugin with same name having `k8s` and `none` target are also considered same for -// backward compatibility reasons. Considering, we are adding `k8s` targeted plugins as root level commands. -// -// E.g. A plugin 'foo' getting discovered/installed with `` target and a plugin `foo` getting discovered -// with `k8s` discovery (having `k8s` target) should be treated as same plugin. -// This function takes this case into consideration and removes `` targeted plugin for above the mentioned scenario. -func combineDuplicatePlugins(availablePlugins []discovery.Discovered) []discovery.Discovered { - mapOfSelectedPlugins := make(map[string]discovery.Discovered) - - // TODO: If there are multiple discovered (but not installed) plugins of the same name then we will - // always end up keeping one deterministically (due to the sequence of sources/plugins that we process), - // but we should merge the result and show the combined result for duplicate plugins - combinePluginInstallationStatus := func(plugin1, plugin2 discovery.Discovered) discovery.Discovered { - // Combine the installation status and installedVersion result when combining plugins - if plugin2.Status == common.PluginStatusInstalled { - plugin1.Status = common.PluginStatusInstalled - } - if plugin2.InstalledVersion != "" { - plugin1.InstalledVersion = plugin2.InstalledVersion - } - return plugin1 - } - - for i := range availablePlugins { - if availablePlugins[i].Target == configtypes.TargetUnknown { - // As we are considering None targeted and k8s target plugin to be treated as same plugins - // in the case of plugin name conflicts, using `k8s` target to determine the plugin already - // exists or not. - // If plugin already exists in the map then combining the installation status for both the plugins - key := fmt.Sprintf("%s_%s", availablePlugins[i].Name, configtypes.TargetK8s) - dp, exists := mapOfSelectedPlugins[key] - if !exists { - mapOfSelectedPlugins[key] = availablePlugins[i] - } else { - mapOfSelectedPlugins[key] = combinePluginInstallationStatus(dp, availablePlugins[i]) - } - } else { - // If plugin doesn't exist in the map then add the plugin to the map - // else combine the installation status for both the plugins - key := fmt.Sprintf("%s_%s", availablePlugins[i].Name, availablePlugins[i].Target) - dp, exists := mapOfSelectedPlugins[key] - if !exists { - mapOfSelectedPlugins[key] = availablePlugins[i] - } else if availablePlugins[i].Target == configtypes.TargetK8s || availablePlugins[i].Scope == common.PluginScopeContext { - mapOfSelectedPlugins[key] = combinePluginInstallationStatus(availablePlugins[i], dp) - } - } - } - - var selectedPlugins []discovery.Discovered - for key := range mapOfSelectedPlugins { - selectedPlugins = append(selectedPlugins, mapOfSelectedPlugins[key]) - } - - return selectedPlugins -} - func mergePluginEntries(plugin1, plugin2 *discovery.Discovered) *discovery.Discovered { // Plugins with the same name having `k8s` and `none` targets are also considered the same for // backward compatibility reasons, considering, we are adding `k8s` targeted plugins as root level commands. @@ -540,46 +362,6 @@ func mergeDuplicateGroups(groups []*plugininventory.PluginGroup) []*plugininvent return mergedGroups } -func getInstalledButNotDiscoveredStandalonePlugins(availablePlugins []discovery.Discovered, installedPlugins []cli.PluginInfo) []discovery.Discovered { - var newPlugins []discovery.Discovered - for i := range installedPlugins { - found := false - for j := range availablePlugins { - if installedPlugins[i].Name == availablePlugins[j].Name && installedPlugins[i].Target == availablePlugins[j].Target { - found = true - // If plugin is installed but marked as not installed as part of availablePlugins list - // mark the plugin as installed - // This is possible if user has used --local mode to install the plugin which is also - // getting discovered from the configured discovery sources - if availablePlugins[j].Status == common.PluginStatusNotInstalled { - availablePlugins[j].Status = common.PluginStatusInstalled - } - } - } - if !found { - p := DiscoveredFromPlugininfo(&installedPlugins[i]) - p.Scope = common.PluginScopeStandalone - p.Status = common.PluginStatusInstalled - p.InstalledVersion = installedPlugins[i].Version - newPlugins = append(newPlugins, p) - } - } - return newPlugins -} - -// DiscoveredFromPlugininfo returns discovered plugin object from k8sV1alpha1 -func DiscoveredFromPlugininfo(p *cli.PluginInfo) discovery.Discovered { - dp := discovery.Discovered{ - Name: p.Name, - Description: p.Description, - RecommendedVersion: p.Version, - Source: p.Discovery, - SupportedVersions: []string{p.Version}, - Target: p.Target, - } - return dp -} - func setAvailablePluginsStatus(availablePlugins []discovery.Discovered, installedPlugins []cli.PluginInfo) { for i := range installedPlugins { for j := range availablePlugins { @@ -596,41 +378,6 @@ func setAvailablePluginsStatus(availablePlugins []discovery.Discovered, installe } } -func availablePluginsFromStandaloneAndServerPlugins(discoveredServerPlugins, discoveredStandalonePlugins []discovery.Discovered) []discovery.Discovered { - availablePlugins := discoveredServerPlugins - - // Check whether the default standalone discovery type is local or not - isLocalStandaloneDiscovery := config.GetDefaultStandaloneDiscoveryType() == common.DiscoveryTypeLocal - - for i := range discoveredStandalonePlugins { - matchIndex := pluginIndexForName(availablePlugins, &discoveredStandalonePlugins[i]) - - // Add the standalone plugin to available plugins if it doesn't exist in the serverPlugins list - // OR - // Current standalone discovery or plugin discovered is of type 'local' - // We are overriding the discovered plugins that we got from server in case of 'local' discovery type - // to allow developers to use the plugins that are built locally and not returned from the server - // This local discovery is only used for development purpose and should not be used for production - if matchIndex < 0 { - availablePlugins = append(availablePlugins, discoveredStandalonePlugins[i]) - continue - } - if isLocalStandaloneDiscovery || discoveredStandalonePlugins[i].DiscoveryType == common.DiscoveryTypeLocal { // matchIndex >= 0 is guaranteed here - availablePlugins[matchIndex] = discoveredStandalonePlugins[i] - } - } - return availablePlugins -} - -func pluginIndexForName(availablePlugins []discovery.Discovered, p *discovery.Discovered) int { - for j := range availablePlugins { - if p != nil && p.Name == availablePlugins[j].Name && p.Target == availablePlugins[j].Target { - return j - } - } - return -1 // haven't found a match -} - // DescribePlugin describes a plugin. func DescribePlugin(pluginName string, target configtypes.Target) (info *cli.PluginInfo, err error) { plugins, err := pluginsupplier.GetInstalledPlugins() @@ -701,12 +448,6 @@ func InstallPluginFromContext(pluginName, version string, target configtypes.Tar // we are installing a standalone plugin. // nolint: gocyclo func installPlugin(pluginName, version string, target configtypes.Target, contextName string) error { - if configlib.IsFeatureActivated(constants.FeatureDisableCentralRepositoryForTesting) { - // The legacy installation can figure out if the plugin is from a context - // because it searches all contexts for plugins. So, we don't need to pass on that parameter. - return legacyPluginInstall(pluginName, version, target) - } - discoveries, err := getPluginDiscoveries() if err != nil { return err @@ -781,41 +522,6 @@ func installPlugin(pluginName, version string, target configtypes.Target, contex return kerrors.NewAggregate(errorList) } -// legacyInstallPlugin installs a plugin by name, version and target. -// This function is only used without the Central Repository feature. -func legacyPluginInstall(pluginName, version string, target configtypes.Target) error { - availablePlugins, err := AvailablePlugins() - if err != nil { - return err - } - - var matchedPlugins []discovery.Discovered - for i := range availablePlugins { - if availablePlugins[i].Name == pluginName && - (target == configtypes.TargetUnknown || target == availablePlugins[i].Target) { - matchedPlugins = append(matchedPlugins, availablePlugins[i]) - } - } - if len(matchedPlugins) == 0 { - if target != configtypes.TargetUnknown { - return errors.Errorf("unable to find plugin '%v' with version '%v' for target '%s'", pluginName, version, string(target)) - } - return errors.Errorf("unable to find plugin '%v' with version '%v'", pluginName, version) - } - - if len(matchedPlugins) == 1 { - return installOrUpgradePlugin(&matchedPlugins[0], version, false) - } - - for i := range matchedPlugins { - if matchedPlugins[i].Target == target { - return installOrUpgradePlugin(&matchedPlugins[i], version, false) - } - } - - return errors.Errorf(missingTargetStr, pluginName) -} - // UpgradePlugin upgrades a plugin from the given repository. func UpgradePlugin(pluginName, version string, target configtypes.Target) error { // Upgrade is only triggered from a manual user operation. @@ -901,60 +607,27 @@ func InstallPluginsFromGroup(pluginName, groupIDAndVersion string, options ...Pl } if !pluginExist { - return "", fmt.Errorf("plugin '%s' is not part of the group '%s'", pluginName, groupIDAndVersion) + return groupIDAndVersion, fmt.Errorf("plugin '%s' is not part of the group '%s'", pluginName, groupIDAndVersion) } if !mandatoryPluginsExist { if pluginName == cli.AllPlugins { - return "", fmt.Errorf("plugin group '%s' has no mandatory plugins to install", groupIDAndVersion) + return groupIDAndVersion, fmt.Errorf("plugin group '%s' has no mandatory plugins to install", groupIDAndVersion) } - return "", fmt.Errorf("plugin '%s' from group '%s' is not mandatory to install", pluginName, groupIDAndVersion) + return groupIDAndVersion, fmt.Errorf("plugin '%s' from group '%s' is not mandatory to install", pluginName, groupIDAndVersion) } if numErrors > 0 { - return "", fmt.Errorf("could not install %d plugin(s) from group '%s'", numErrors, groupIDAndVersion) + return groupIDAndVersion, fmt.Errorf("could not install %d plugin(s) from group '%s'", numErrors, groupIDAndVersion) } if numInstalled == 0 { - return "", fmt.Errorf("plugin '%s' is not part of the group '%s'", pluginName, groupIDAndVersion) + return groupIDAndVersion, fmt.Errorf("plugin '%s' is not part of the group '%s'", pluginName, groupIDAndVersion) } return groupIDAndVersion, nil } -// GetRecommendedVersionOfPlugin returns recommended version of the plugin -func GetRecommendedVersionOfPlugin(pluginName string, target configtypes.Target) (string, error) { - availablePlugins, err := AvailablePlugins() - if err != nil { - return "", err - } - - var matchedPlugins []discovery.Discovered - for i := range availablePlugins { - if availablePlugins[i].Name == pluginName && - (target == configtypes.TargetUnknown || target == availablePlugins[i].Target) { - matchedPlugins = append(matchedPlugins, availablePlugins[i]) - } - } - if len(matchedPlugins) == 0 { - if target != configtypes.TargetUnknown { - return "", errors.Errorf("unable to find plugin '%v' for target '%s'", pluginName, string(target)) - } - return "", errors.Errorf("unable to find plugin '%v'", pluginName) - } - - if len(matchedPlugins) == 1 { - return matchedPlugins[0].RecommendedVersion, nil - } - - for i := range matchedPlugins { - if matchedPlugins[i].Target == target { - return matchedPlugins[i].RecommendedVersion, nil - } - } - return "", errors.Errorf(missingTargetStr, pluginName) -} - func installOrUpgradePlugin(p *discovery.Discovered, version string, installTestPlugin bool) error { if p.Target == configtypes.TargetUnknown { log.Infof("Installing plugin '%v:%v'", p.Name, version) @@ -1246,31 +919,22 @@ func doDeletePluginFromCatalog(pluginName string, target configtypes.Target, cat // If the central-repo is disabled, all discovered plugins will be installed. func SyncPlugins() error { log.Info("Checking for required plugins...") - var plugins []discovery.Discovered - var err error errList := make([]error, 0) - if !configlib.IsFeatureActivated(constants.FeatureDisableCentralRepositoryForTesting) { - // We no longer sync standalone plugins. - // With a centralized approach to discovering plugins, synchronizing - // standalone plugins would install ALL plugins available for ALL - // products. - // Instead, we only synchronize any plugins that are specifically specified - // by the contexts. - // - // Note: to install all plugins for a specific product, plugin groups will - // need to be used. - plugins, err = DiscoverServerPlugins() - if err != nil { - errList = append(errList, err) - } - if installedPlugins, err := pluginsupplier.GetInstalledServerPlugins(); err == nil { - setAvailablePluginsStatus(plugins, installedPlugins) - } - } else { - plugins, err = AvailablePlugins() - if err != nil { - errList = append(errList, err) - } + // We no longer sync standalone plugins. + // With a centralized approach to discovering plugins, synchronizing + // standalone plugins would install ALL plugins available for ALL + // products. + // Instead, we only synchronize any plugins that are specifically specified + // by the contexts. + // + // Note: to install all plugins for a specific product, plugin groups will + // need to be used. + plugins, err := DiscoverServerPlugins() + if err != nil { + errList = append(errList, err) + } + if installedPlugins, err := pluginsupplier.GetInstalledServerPlugins(); err == nil { + setAvailablePluginsStatus(plugins, installedPlugins) } installed := false @@ -1402,7 +1066,7 @@ func discoverPluginsFromLocalSource(localPath string) ([]discovery.Discovered, e } } - plugins, err := discoverPlugins(pds) + plugins, err := discoverSpecificPlugins(pds) if err != nil { log.Warningf(errorWhileDiscoveringPlugins, err.Error()) } @@ -1663,11 +1327,8 @@ func FindVersion(recommendedPluginVersion, requestedVersion string) string { // getPluginDiscoveries returns the plugin discoveries found in the configuration file. func getPluginDiscoveries() ([]configtypes.PluginDiscovery, error) { - var testDiscoveries []configtypes.PluginDiscovery - if !configlib.IsFeatureActivated(constants.FeatureDisableCentralRepositoryForTesting) { - // Look for testing discoveries. Those should be stored and searched AFTER the central repo. - testDiscoveries = GetAdditionalTestPluginDiscoveries() - } + // Look for testing discoveries. Those should be stored and searched AFTER the central repo. + testDiscoveries := GetAdditionalTestPluginDiscoveries() // The configured discoveries should be searched BEFORE the test discoveries. // For example, if the staging central repo is added as a test discovery, it diff --git a/pkg/pluginmanager/manager_helper_test.go b/pkg/pluginmanager/manager_helper_test.go index 85a4aa3bf..bdecae440 100644 --- a/pkg/pluginmanager/manager_helper_test.go +++ b/pkg/pluginmanager/manager_helper_test.go @@ -4,10 +4,15 @@ package pluginmanager import ( + "database/sql" + "fmt" "os" "os/exec" "path/filepath" + // Import the sqlite driver + _ "modernc.org/sqlite" + "github.com/otiai10/copy" "github.com/stretchr/testify/assert" @@ -18,9 +23,97 @@ import ( "github.com/vmware-tanzu/tanzu-cli/pkg/common" "github.com/vmware-tanzu/tanzu-cli/pkg/config" "github.com/vmware-tanzu/tanzu-cli/pkg/discovery" + "github.com/vmware-tanzu/tanzu-cli/pkg/plugininventory" "github.com/vmware-tanzu/tanzu-plugin-runtime/log" ) +var testPlugins = []plugininventory.PluginIdentifier{ + {Name: "management-cluster", Target: configtypes.TargetK8s, Version: "v1.6.0"}, + {Name: "cluster", Target: configtypes.TargetK8s, Version: "v1.6.0"}, + {Name: "myplugin", Target: configtypes.TargetK8s, Version: "v1.6.0"}, + {Name: "feature", Target: configtypes.TargetK8s, Version: "v0.2.0"}, + + {Name: "isolated-cluster", Target: configtypes.TargetGlobal, Version: "v1.2.3"}, + {Name: "isolated-cluster", Target: configtypes.TargetGlobal, Version: "v1.3.0"}, + {Name: "login", Target: configtypes.TargetGlobal, Version: "v0.2.0"}, + + {Name: "management-cluster", Target: configtypes.TargetTMC, Version: "v0.0.1"}, + {Name: "management-cluster", Target: configtypes.TargetTMC, Version: "v0.0.2"}, + {Name: "management-cluster", Target: configtypes.TargetTMC, Version: "v0.0.3"}, + {Name: "management-cluster", Target: configtypes.TargetTMC, Version: "v0.2.0"}, + {Name: "cluster", Target: configtypes.TargetTMC, Version: "v0.2.0"}, + {Name: "myplugin", Target: configtypes.TargetTMC, Version: "v0.2.0"}, +} + +const createGroupsStmt = ` +INSERT INTO PluginGroups VALUES( + 'vmware', + 'test', + 'default', + 'v1.6.0', + 'Description for vmware-test/default:v1.6.0', + 'management-cluster', + 'kubernetes', + 'v1.6.0', + 'true', + 'false'); +INSERT INTO PluginGroups VALUES( + 'vmware', + 'test', + 'default', + 'v1.6.0', + 'Description for vmware-test/default:v1.6.0', + 'feature', + 'kubernetes', + 'v0.2.0', + 'true', + 'false'); +INSERT INTO PluginGroups VALUES( + 'vmware', + 'test', + 'default', + 'v1.6.0', + 'Description for vmware-test/default:v1.6.0', + 'myplugin', + 'kubernetes', + 'v1.6.0', + 'true', + 'false'); +INSERT INTO PluginGroups VALUES( + 'vmware', + 'test', + 'default', + 'v1.6.0', + 'Description for vmware-test/default:v1.6.0', + 'isolated-cluster', + 'global', + 'v1.2.3', + 'true', + 'false'); +INSERT INTO PluginGroups VALUES( + 'vmware', + 'test', + 'default', + 'v1.6.0', + 'Description for vmware-test/default:v1.6.0', + 'cluster', + 'kubernetes', + 'v1.6.0', + 'false', + 'false'); +INSERT INTO PluginGroups VALUES( + 'vmware', + 'test', + 'default', + 'v2.1.0', + 'Description for vmware-test/default:v2.1.0', + 'isolated-cluster', + 'global', + 'v1.3.0', + 'true', + 'false'); +` + func findDiscoveredPlugin(discovered []discovery.Discovered, pluginName string, target configtypes.Target) *discovery.Discovered { for i := range discovered { if pluginName == discovered[i].Name && target == discovered[i].Target { @@ -39,6 +132,158 @@ func findPluginInfo(pd []cli.PluginInfo, pluginName string, target configtypes.T return nil } +func findGroupVersion(allGroups []*plugininventory.PluginGroup, id string) bool { + groupID := plugininventory.PluginGroupIdentifierFromID(id) + for _, g := range allGroups { + if g.Publisher == groupID.Publisher && + g.Vendor == groupID.Vendor && + g.Name == groupID.Name { + for v := range g.Versions { + if v == groupID.Version { + return true + } + } + } + } + return false +} + +func setupPluginBinaryInCache(name, version string, target configtypes.Target, digest string) { + dir := filepath.Join(common.DefaultPluginRoot, name) + err := os.MkdirAll(dir, 0755) + if err != nil { + log.Fatal(err, "unable to create temporary directory for plugin binary") + } + + pluginBinary := filepath.Join(dir, fmt.Sprintf("%s_%s_%s", version, digest, target)) + f, err := os.OpenFile(pluginBinary, os.O_CREATE|os.O_WRONLY, 0755) + if err != nil { + log.Fatal(err, "unable to create temporary plugin binary") + } + defer f.Close() + + _, err = fmt.Fprintf(f, + `{"name":"%s", +"description":"Test plugin", +"target":"%s", +"version": "%s", +"buildSHA":"c2dbd15", +"digest":"%s", +"group":"Run", +"docURL":"", +"completionType":0, +"aliases":["test"], +"installationPath":"", +"discovery":"", +"scope":"", +"status":""}`, name, target, version, digest) + + if err != nil { + log.Fatal(err, fmt.Sprintf("Error while generating plugin binary %s", pluginBinary)) + } +} + +func setupPluginEntriesAndBinaries(db *sql.DB) { + digest := "0000000000" + for _, plugin := range testPlugins { + desc := fmt.Sprintf("Plugin %s description", plugin.Name) + for _, osArch := range cli.AllOSArch { + uri := fmt.Sprintf("vmware/test/%s/%s/%s/%s:%s", osArch.OS(), osArch.Arch(), plugin.Target, plugin.Name, plugin.Version) + + _, err := db.Exec("INSERT INTO PluginBinaries (PluginName,Target,RecommendedVersion,Version,Hidden,Description,Publisher,Vendor,OS,Architecture,Digest,URI) VALUES(?,?,'',?,'false',?,'test','vmware',?,?,?,?);", plugin.Name, plugin.Target, plugin.Version, desc, osArch.OS(), osArch.Arch(), digest, uri) + + if err != nil { + log.Fatal(err, fmt.Sprintf("failed to create %s:%s for target %s for testing", plugin.Name, plugin.Version, plugin.Target)) + } + } + setupPluginBinaryInCache(plugin.Name, plugin.Version, plugin.Target, digest) + } +} + +func setupTestPluginInventory() { + // Create a temporary directory for the plugin inventory DB + inventoryDir := filepath.Join( + common.DefaultCacheDir, + common.PluginInventoryDirName, + config.DefaultStandaloneDiscoveryName) + err := os.MkdirAll(inventoryDir, 0755) + if err != nil { + log.Fatal(err, "unable to create temporary directory for plugin inventory") + } + + // Generate a test plugin inventory DB + dbFile, err := os.Create(filepath.Join(inventoryDir, plugininventory.SQliteDBFileName)) + if err != nil { + log.Fatal(err, "unable to create temporary file for plugin inventory") + } + // Open DB with the sqlite driver + db, err := sql.Open("sqlite", dbFile.Name()) + if err != nil { + log.Fatal(err, "unable to open create temporary plugin inventory DB") + } + defer db.Close() + + // Create the table + _, err = db.Exec(plugininventory.CreateTablesSchema) + if err != nil { + log.Fatal(err, "failed to create DB table for testing") + } + + // Add plugin entries to the DB and create the corresponding binaries + setupPluginEntriesAndBinaries(db) + + // Add plugin group entries to the DB + _, err = db.Exec(createGroupsStmt) + if err != nil { + log.Fatal(err, "failed to create plugin groups for testing") + } +} + +func setupPluginSourceForTesting() func() { + tmpDir, err := os.MkdirTemp(os.TempDir(), "") + if err != nil { + log.Fatal(err, "unable to create temporary directory") + } + + common.DefaultPluginRoot = filepath.Join(tmpDir, "plugin-root") + + // Setup the two temporary configuration files + configFile := filepath.Join(tmpDir, "tanzu_config.yaml") + configNextGenFile := filepath.Join(tmpDir, "tanzu_config_ng.yaml") + os.Setenv("TANZU_CONFIG", configFile) + os.Setenv("TANZU_CONFIG_NEXT_GEN", configNextGenFile) + + // Setup both test configuration files + err = copy.Copy(filepath.Join("test", "config.yaml"), configFile) + if err != nil { + log.Fatal(err, "Error while coping tanzu config file for testing") + } + + err = copy.Copy(filepath.Join("test", "config-ng2.yaml"), configNextGenFile) + if err != nil { + log.Fatal(err, "Error while coping tanzu config next gen file for testing") + } + + // Setup a temporary cache directory + common.DefaultCacheDir = filepath.Join(tmpDir, "cache") + + common.DefaultLocalPluginDistroDir = filepath.Join(tmpDir, "distro") + err = copy.Copy(filepath.Join("test", "local"), common.DefaultLocalPluginDistroDir) + if err != nil { + log.Fatal(err, "Error while setting local distro for testing") + } + + setupTestPluginInventory() + os.Setenv("TEST_TANZU_CLI_USE_DB_CACHE_ONLY", "1") + + return func() { + os.RemoveAll(tmpDir) + os.Unsetenv("TANZU_CONFIG") + os.Unsetenv("TANZU_CONFIG_NEXT_GEN") + os.Unsetenv("TEST_TANZU_CLI_USE_DB_CACHE_ONLY") + } +} + func setupLocalDistroForTesting() func() { tmpDir, err := os.MkdirTemp(os.TempDir(), "") if err != nil { diff --git a/pkg/pluginmanager/manager_test.go b/pkg/pluginmanager/manager_test.go index 980480d97..1468b0915 100644 --- a/pkg/pluginmanager/manager_test.go +++ b/pkg/pluginmanager/manager_test.go @@ -8,13 +8,11 @@ import ( "os" "os/exec" "path/filepath" - "strings" "testing" "github.com/pkg/errors" "github.com/stretchr/testify/assert" - configlib "github.com/vmware-tanzu/tanzu-plugin-runtime/config" configtypes "github.com/vmware-tanzu/tanzu-plugin-runtime/config/types" "github.com/vmware-tanzu/tanzu-cli/pkg/cli" @@ -25,7 +23,6 @@ import ( "github.com/vmware-tanzu/tanzu-cli/pkg/distribution" "github.com/vmware-tanzu/tanzu-cli/pkg/plugininventory" "github.com/vmware-tanzu/tanzu-cli/pkg/pluginsupplier" - "github.com/vmware-tanzu/tanzu-plugin-runtime/log" ) var expectedDiscoveredContextPlugins = []discovery.Discovered{ @@ -53,181 +50,152 @@ var expectedDiscoveredContextPlugins = []discovery.Discovered{ } var expectedDiscoveredStandalonePlugins = []discovery.Discovered{ { - Name: "login", - RecommendedVersion: "v0.2.0", + Name: "management-cluster", + Description: "Plugin management-cluster description", + RecommendedVersion: "v1.6.0", + SupportedVersions: []string{"v1.6.0"}, Scope: common.PluginScopeStandalone, ContextName: "", - Target: configtypes.TargetUnknown, + Target: configtypes.TargetK8s, }, { - Name: "feature", - RecommendedVersion: "v0.2.0", + Name: "cluster", + Description: "Plugin cluster description", + RecommendedVersion: "v1.6.0", + SupportedVersions: []string{"v1.6.0"}, Scope: common.PluginScopeStandalone, ContextName: "", Target: configtypes.TargetK8s, }, { - Name: "management-cluster", + Name: "myplugin", + Description: "Plugin myplugin description", RecommendedVersion: "v1.6.0", + SupportedVersions: []string{"v1.6.0"}, Scope: common.PluginScopeStandalone, ContextName: "", Target: configtypes.TargetK8s, }, { - Name: "myplugin", - RecommendedVersion: "v1.6.0", + Name: "feature", + Description: "Plugin feature description", + RecommendedVersion: "v0.2.0", + SupportedVersions: []string{"v0.2.0"}, Scope: common.PluginScopeStandalone, ContextName: "", Target: configtypes.TargetK8s, }, + { + Name: "isolated-cluster", + Description: "Plugin isolated-cluster description", + RecommendedVersion: "v1.3.0", + SupportedVersions: []string{"v1.2.3", "v1.3.0"}, + Scope: common.PluginScopeStandalone, + ContextName: "", + Target: configtypes.TargetGlobal, + }, + { + Name: "login", + Description: "Plugin login description", + RecommendedVersion: "v0.2.0", + SupportedVersions: []string{"v0.2.0"}, + Scope: common.PluginScopeStandalone, + ContextName: "", + Target: configtypes.TargetGlobal, + }, + { + Name: "management-cluster", + Description: "Plugin management-cluster description", + RecommendedVersion: "v0.2.0", + SupportedVersions: []string{"v0.0.1", "v0.0.2", "v0.0.3", "v0.2.0"}, + Scope: common.PluginScopeStandalone, + ContextName: "", + Target: configtypes.TargetTMC, + }, + { + Name: "cluster", + Description: "Plugin cluster description", + RecommendedVersion: "v0.2.0", + SupportedVersions: []string{"v0.2.0"}, + Scope: common.PluginScopeStandalone, + ContextName: "", + Target: configtypes.TargetTMC, + }, { Name: "myplugin", + Description: "Plugin myplugin description", RecommendedVersion: "v0.2.0", + SupportedVersions: []string{"v0.2.0"}, Scope: common.PluginScopeStandalone, ContextName: "", Target: configtypes.TargetTMC, }, } -func Test_DiscoverPlugins(t *testing.T) { +var expectedDiscoveredGroups = []string{"vmware-test/default:v1.6.0", "vmware-test/default:v2.1.0"} + +const ( + testGroupName = "vmware-test/default" + testGroupVersion = "v1.6.0" +) + +func Test_DiscoverStandalonePlugins(t *testing.T) { assertions := assert.New(t) - defer setupLocalDistroForTesting()() + defer setupPluginSourceForTesting()() - serverPlugins, standalonePlugins := DiscoverPlugins() - assertions.Equal(len(expectedDiscoveredContextPlugins), len(serverPlugins)) + standalonePlugins, err := DiscoverStandalonePlugins() + assertions.Nil(err) assertions.Equal(len(expectedDiscoveredStandalonePlugins), len(standalonePlugins)) - discoveredPlugins := append(serverPlugins, standalonePlugins...) - expectedDiscoveredPlugins := append(expectedDiscoveredContextPlugins, expectedDiscoveredStandalonePlugins...) - - for i := 0; i < len(expectedDiscoveredPlugins); i++ { - p := findDiscoveredPlugin(discoveredPlugins, expectedDiscoveredPlugins[i].Name, expectedDiscoveredPlugins[i].Target) + for i := range expectedDiscoveredStandalonePlugins { + p := findDiscoveredPlugin(standalonePlugins, expectedDiscoveredStandalonePlugins[i].Name, expectedDiscoveredStandalonePlugins[i].Target) assertions.NotNil(p) - assertions.Equal(expectedDiscoveredPlugins[i].Name, p.Name) - assertions.Equal(expectedDiscoveredPlugins[i].RecommendedVersion, p.RecommendedVersion) - assertions.Equal(expectedDiscoveredPlugins[i].Target, p.Target) + assertions.Equal(expectedDiscoveredStandalonePlugins[i].Description, p.Description) + assertions.Equal(expectedDiscoveredStandalonePlugins[i].RecommendedVersion, p.RecommendedVersion) + assertions.Equal(expectedDiscoveredStandalonePlugins[i].SupportedVersions, p.SupportedVersions) + assertions.Equal(expectedDiscoveredStandalonePlugins[i].Scope, p.Scope) + assertions.Equal(expectedDiscoveredStandalonePlugins[i].ContextName, p.ContextName) } - - err := configlib.SetFeature("global", "context-target-v2", "false") - assertions.Nil(err) - - serverPlugins, standalonePlugins = DiscoverPlugins() - assertions.Equal(1, len(serverPlugins)) - assertions.Equal(len(expectedDiscoveredStandalonePlugins), len(standalonePlugins)) } -func Test_InstallPlugin_InstalledPlugins_No_Central_Repo(t *testing.T) { +func Test_DiscoverServerPlugins(t *testing.T) { assertions := assert.New(t) - defer setupLocalDistroForTesting()() - execCommand = fakeInfoExecCommand - defer func() { execCommand = exec.Command }() - - // Turn off central repo feature - featureArray := strings.Split(constants.FeatureDisableCentralRepositoryForTesting, ".") - err := configlib.SetFeature(featureArray[1], featureArray[2], "true") - assertions.Nil(err) - - // Try installing nonexistent plugin - err = InstallStandalonePlugin("not-exists", "v0.2.0", configtypes.TargetUnknown) - assertions.NotNil(err) - assertions.Contains(err.Error(), "unable to find plugin 'not-exists'") - - // Install login (standalone) plugin - err = InstallStandalonePlugin("login", "v0.2.0", configtypes.TargetUnknown) - assertions.Nil(err) - // Verify installed plugin - installedPlugins, err := pluginsupplier.GetInstalledPlugins() - assertions.Nil(err) - assertions.Equal(1, len(installedPlugins)) - assertions.Equal("login", installedPlugins[0].Name) + defer setupPluginSourceForTesting()() - // Try installing cluster plugin with no context-type - err = InstallStandalonePlugin("cluster", "v0.2.0", configtypes.TargetUnknown) + serverPlugins, err := DiscoverServerPlugins() assertions.NotNil(err) - assertions.Contains(err.Error(), fmt.Sprintf(missingTargetStr, "cluster")) - - // Try installing cluster plugin with context-type=tmc - err = InstallStandalonePlugin("cluster", "v0.2.0", configtypes.TargetTMC) - assertions.Nil(err) - - // Try installing cluster plugin through context-type=k8s with incorrect version - err = InstallStandalonePlugin("cluster", "v1.0.0", configtypes.TargetK8s) - assertions.NotNil(err) - assertions.Contains(err.Error(), "plugin pre-download verification failed") + assertions.Contains(err.Error(), "unable to list plugins from discovery source 'default-mgmt': Failed to load Kubeconfig file") + assertions.Equal(len(expectedDiscoveredContextPlugins), len(serverPlugins)) - // Try installing cluster plugin through context-type=k8s - err = InstallStandalonePlugin("cluster", "v1.6.0", configtypes.TargetK8s) - assertions.Nil(err) + for i := range expectedDiscoveredContextPlugins { + p := findDiscoveredPlugin(serverPlugins, expectedDiscoveredContextPlugins[i].Name, expectedDiscoveredContextPlugins[i].Target) + assertions.NotNil(p) + assertions.Equal(expectedDiscoveredContextPlugins[i].RecommendedVersion, p.RecommendedVersion) + assertions.Equal(expectedDiscoveredContextPlugins[i].Scope, p.Scope) + assertions.Equal(expectedDiscoveredContextPlugins[i].ContextName, p.ContextName) + } +} - // Try installing management-cluster plugin from standalone discovery without context-type - err = InstallStandalonePlugin("management-cluster", "v1.6.0", configtypes.TargetUnknown) - assertions.NotNil(err) - assertions.Contains(err.Error(), fmt.Sprintf(missingTargetStr, "management-cluster")) +func Test_DiscoverPluginGroups(t *testing.T) { + assertions := assert.New(t) - // Try installing management-cluster plugin from standalone discovery - err = InstallStandalonePlugin("management-cluster", "v1.6.0", configtypes.TargetK8s) - assertions.Nil(err) + defer setupPluginSourceForTesting()() - // Try installing the feature plugin which is targeted for k8s but requesting the TMC target - err = InstallStandalonePlugin("feature", "v0.2.0", configtypes.TargetTMC) - assertions.NotNil(err) - assertions.Contains(err.Error(), "unable to find plugin 'feature' with version 'v0.2.0' for target 'mission-control'") - - // Verify installed plugins - installedStandalonePlugins, err := pluginsupplier.GetInstalledStandalonePlugins() + groups, err := DiscoverPluginGroups() assertions.Nil(err) - assertions.Equal(2, len(installedStandalonePlugins)) - installedServerPlugins, err := pluginsupplier.GetInstalledServerPlugins() - assertions.Nil(err) - assertions.Equal(2, len(installedServerPlugins)) - expectedInstalledServerPlugins := []cli.PluginInfo{ - { - Name: "cluster", - Version: "v1.6.0", - Scope: common.PluginScopeContext, - Target: configtypes.TargetK8s, - }, - { - Name: "cluster", - Version: "v0.2.0", - Scope: common.PluginScopeContext, - Target: configtypes.TargetTMC, - }, - } - expectedInstalledStandalonePlugins := []cli.PluginInfo{ - { - Name: "login", - Version: "v0.2.0", - Scope: common.PluginScopeStandalone, - Target: configtypes.TargetUnknown, - }, - { - Name: "management-cluster", - Version: "v1.6.0", - Scope: common.PluginScopeStandalone, - Target: configtypes.TargetK8s, - }, - } - - for i := 0; i < len(expectedInstalledServerPlugins); i++ { - pd := findPluginInfo(installedServerPlugins, expectedInstalledServerPlugins[i].Name, expectedInstalledServerPlugins[i].Target) - assertions.NotNil(pd) - assertions.Equal(expectedInstalledServerPlugins[i].Version, pd.Version) - } - for i := 0; i < len(expectedInstalledStandalonePlugins); i++ { - pd := findPluginInfo(installedStandalonePlugins, expectedInstalledStandalonePlugins[i].Name, expectedInstalledStandalonePlugins[i].Target) - assertions.NotNil(pd) - assertions.Equal(expectedInstalledStandalonePlugins[i].Version, pd.Version) + for _, id := range expectedDiscoveredGroups { + found := findGroupVersion(groups, id) + assertions.True(found, fmt.Sprintf("unable to find group %s", id)) } } -func Test_InstallPlugin_InstalledPlugins_Central_Repo(t *testing.T) { +func Test_InstallStandalonePlugin(t *testing.T) { assertions := assert.New(t) - defer setupLocalDistroForTesting()() + defer setupPluginSourceForTesting()() execCommand = fakeInfoExecCommand defer func() { execCommand = exec.Command }() @@ -245,25 +213,25 @@ func Test_InstallPlugin_InstalledPlugins_Central_Repo(t *testing.T) { assertions.Equal(1, len(installedPlugins)) assertions.Equal("login", installedPlugins[0].Name) - // Try installing myplugin plugin with no context-type - err = InstallStandalonePlugin("myplugin", "v0.2.0", configtypes.TargetUnknown) + // Try installing myplugin plugin with no context-type and no specific version + err = InstallStandalonePlugin("myplugin", cli.VersionLatest, configtypes.TargetUnknown) assertions.NotNil(err) assertions.Contains(err.Error(), fmt.Sprintf(missingTargetStr, "myplugin")) - // Try installing myplugin plugin with context-type=tmc - err = InstallStandalonePlugin("myplugin", "v0.2.0", configtypes.TargetTMC) + // Try installing myplugin plugin with context-type=tmc with no specific version + err = InstallStandalonePlugin("myplugin", cli.VersionLatest, configtypes.TargetTMC) assertions.Nil(err) // Try installing myplugin plugin through context-type=k8s with incorrect version err = InstallStandalonePlugin("myplugin", "v1.0.0", configtypes.TargetK8s) assertions.NotNil(err) - assertions.Contains(err.Error(), "plugin pre-download verification failed") + assertions.Contains(err.Error(), "unable to find plugin 'myplugin' with version 'v1.0.0'") - // Try installing myplugin plugin through context-type=k8s + // Try installing myplugin plugin through context-type=k8s with the correct version err = InstallStandalonePlugin("myplugin", "v1.6.0", configtypes.TargetK8s) assertions.Nil(err) - // Try installing management-cluster plugin from standalone discovery + // Try installing management-cluster plugin err = InstallStandalonePlugin("management-cluster", "v1.6.0", configtypes.TargetK8s) assertions.Nil(err) @@ -285,7 +253,7 @@ func Test_InstallPlugin_InstalledPlugins_Central_Repo(t *testing.T) { Name: "login", Version: "v0.2.0", Scope: common.PluginScopeStandalone, - Target: configtypes.TargetUnknown, + Target: configtypes.TargetGlobal, }, { Name: "management-cluster", @@ -314,23 +282,76 @@ func Test_InstallPlugin_InstalledPlugins_Central_Repo(t *testing.T) { } } -func Test_InstallPluginFromGroup(t *testing.T) { +func Test_InstallPluginsFromGroup(t *testing.T) { assertions := assert.New(t) - defer setupLocalDistroForTesting()() + defer setupPluginSourceForTesting()() execCommand = fakeInfoExecCommand defer func() { execCommand = exec.Command }() - // A local discovery currently does not support groups, but we can - // at least do negative testing - groupID := "vmware-tkg/default:v2.1.0" - _, err := InstallPluginsFromGroup("cluster", groupID) - assertions.NotNil(err) - assertions.Contains(err.Error(), "unable to create group discovery: unknown group discovery source") + // Install the management-cluster plugin from a group:version + groupID := testGroupName + ":" + testGroupVersion + fullGroupID, err := InstallPluginsFromGroup("management-cluster", groupID) + assertions.Nil(err) + assertions.Equal(groupID, fullGroupID) + + installedStandalonePlugins, err := pluginsupplier.GetInstalledStandalonePlugins() + assertions.Nil(err) + assertions.Equal(1, len(installedStandalonePlugins)) + pd := findPluginInfo(installedStandalonePlugins, "management-cluster", configtypes.TargetK8s) + assertions.NotNil(pd) + assertions.Equal("v1.6.0", pd.Version) + + // Install the isolated-cluster from the latest group + groupID = testGroupName + fullGroupID, err = InstallPluginsFromGroup("isolated-cluster", groupID) + assertions.Nil(err) + assertions.Equal(groupID+":v2.1.0", fullGroupID) + + installedStandalonePlugins, err = pluginsupplier.GetInstalledStandalonePlugins() + assertions.Nil(err) + assertions.Equal(2, len(installedStandalonePlugins)) + pd = findPluginInfo(installedStandalonePlugins, "management-cluster", configtypes.TargetK8s) + assertions.NotNil(pd) + assertions.Equal("v1.6.0", pd.Version) + pd = findPluginInfo(installedStandalonePlugins, "isolated-cluster", configtypes.TargetGlobal) + assertions.NotNil(pd) + assertions.Equal("v1.3.0", pd.Version) + + // Install all plugins from a group:version + // Note that this should replace isolated-cluster:v1.3.0 with its v1.2.3 version + groupID = testGroupName + ":" + testGroupVersion + fullGroupID, err = InstallPluginsFromGroup(cli.AllPlugins, groupID) + assertions.Nil(err) + assertions.Equal(groupID, fullGroupID) + + installedStandalonePlugins, err = pluginsupplier.GetInstalledStandalonePlugins() + assertions.Nil(err) + assertions.Equal(4, len(installedStandalonePlugins)) + pd = findPluginInfo(installedStandalonePlugins, "management-cluster", configtypes.TargetK8s) + assertions.NotNil(pd) + assertions.Equal("v1.6.0", pd.Version) + pd = findPluginInfo(installedStandalonePlugins, "isolated-cluster", configtypes.TargetGlobal) + assertions.NotNil(pd) + assertions.Equal("v1.2.3", pd.Version) + pd = findPluginInfo(installedStandalonePlugins, "myplugin", configtypes.TargetK8s) + assertions.NotNil(pd) + assertions.Equal("v1.6.0", pd.Version) + pd = findPluginInfo(installedStandalonePlugins, "feature", configtypes.TargetK8s) + assertions.NotNil(pd) + assertions.Equal("v0.2.0", pd.Version) +} + +func Test_InstallPluginsFromGroupErrors(t *testing.T) { + assertions := assert.New(t) + + defer setupPluginSourceForTesting()() + execCommand = fakeInfoExecCommand + defer func() { execCommand = exec.Command }() // make sure a poorly formatted group is properly handled - groupID = "invalid" - _, err = InstallPluginsFromGroup("cluster", groupID) + groupID := "invalid" + _, err := InstallPluginsFromGroup("cluster", groupID) assertions.NotNil(err) assertions.Contains(err.Error(), "could not find group") @@ -353,295 +374,18 @@ func Test_InstallPluginFromGroup(t *testing.T) { _, err = InstallPluginsFromGroup("cluster", groupID) assertions.NotNil(err) assertions.Contains(err.Error(), "could not find group") -} -func Test_DiscoverPluginGroups(t *testing.T) { - assertions := assert.New(t) - - defer setupLocalDistroForTesting()() - execCommand = fakeInfoExecCommand - defer func() { execCommand = exec.Command }() - - // A local discovery currently does not support groups, but we can - // at least do negative testing - _, err := DiscoverPluginGroups(nil) + groupID = testGroupName + fullGroupID, err := InstallPluginsFromGroup("cluster", groupID) assertions.NotNil(err) - assertions.Contains(err.Error(), "unable to create group discovery: unknown group discovery source") -} - -func Test_AvailablePlugins(t *testing.T) { - assertions := assert.New(t) - - defer setupLocalDistroForTesting()() - - expectedDiscoveredPlugins := append(expectedDiscoveredContextPlugins, expectedDiscoveredStandalonePlugins...) - discoveredPlugins, err := AvailablePlugins() - assertions.Nil(err) - assertions.Equal(len(expectedDiscoveredPlugins), len(discoveredPlugins)) - - for i := 0; i < len(expectedDiscoveredPlugins); i++ { - pd := findDiscoveredPlugin(discoveredPlugins, expectedDiscoveredPlugins[i].Name, expectedDiscoveredPlugins[i].Target) - assertions.NotNil(pd) - assertions.Equal(expectedDiscoveredPlugins[i].Name, pd.Name) - assertions.Equal(expectedDiscoveredPlugins[i].RecommendedVersion, pd.RecommendedVersion) - assertions.Equal(expectedDiscoveredPlugins[i].Target, pd.Target) - assertions.Equal(expectedDiscoveredPlugins[i].Scope, pd.Scope) - assertions.Equal(common.PluginStatusNotInstalled, pd.Status) - } - - // Install login, myplugin plugins - mockInstallPlugin(assertions, "login", "v0.2.0", configtypes.TargetUnknown) - mockInstallPlugin(assertions, "myplugin", "v0.2.0", configtypes.TargetTMC) - - expectedInstallationStatusOfPlugins := []discovery.Discovered{ - { - Name: "myplugin", - Target: configtypes.TargetTMC, - InstalledVersion: "v0.2.0", - Status: common.PluginStatusInstalled, - }, - { - Name: "myplugin", - Target: configtypes.TargetK8s, - InstalledVersion: "", - Status: common.PluginStatusNotInstalled, - }, - { - Name: "login", - Target: configtypes.TargetUnknown, - InstalledVersion: "v0.2.0", - Status: common.PluginStatusInstalled, - }, - } - - // Get available plugin after install and verify installation status - discoveredPlugins, err = AvailablePlugins() - assertions.Nil(err) - assertions.Equal(len(expectedDiscoveredPlugins), len(discoveredPlugins)) - - for _, eisp := range expectedInstallationStatusOfPlugins { - p := findDiscoveredPlugin(discoveredPlugins, eisp.Name, eisp.Target) - assertions.NotNil(p) - assertions.Equal(eisp.Status, p.Status) - assertions.Equal(eisp.InstalledVersion, p.InstalledVersion) - } - - // Install management-cluster, feature plugins - mockInstallPlugin(assertions, "management-cluster", "v1.6.0", configtypes.TargetK8s) - mockInstallPlugin(assertions, "feature", "v0.2.0", configtypes.TargetK8s) + assertions.Equal(groupID+":v2.1.0", fullGroupID) + assertions.Contains(err.Error(), fmt.Sprintf("plugin 'cluster' is not part of the group '%s'", fullGroupID)) - expectedInstallationStatusOfPlugins = []discovery.Discovered{ - { - Name: "management-cluster", - Target: configtypes.TargetK8s, - InstalledVersion: "v1.6.0", - Status: common.PluginStatusInstalled, - }, - { - Name: "feature", - Target: configtypes.TargetK8s, - InstalledVersion: "v0.2.0", - Status: common.PluginStatusInstalled, - }, - { - Name: "management-cluster", - Target: configtypes.TargetTMC, - InstalledVersion: "", - Status: common.PluginStatusNotInstalled, - }, - { - Name: "login", - Target: configtypes.TargetUnknown, - InstalledVersion: "v0.2.0", - Status: common.PluginStatusInstalled, - }, - } - - // Get available plugin after install and verify installation status - discoveredPlugins, err = AvailablePlugins() - assertions.Nil(err) - assertions.Equal(len(expectedDiscoveredPlugins), len(discoveredPlugins)) - - for _, eisp := range expectedInstallationStatusOfPlugins { - p := findDiscoveredPlugin(discoveredPlugins, eisp.Name, eisp.Target) - assertions.NotNil(p) - assertions.Equal(eisp.Status, p.Status, eisp.Name) - assertions.Equal(eisp.InstalledVersion, p.InstalledVersion, eisp.Name) - } -} - -func Test_AvailablePlugins_With_K8s_None_Target_Plugin_Name_Conflict_With_One_Installed_Getting_Discovered(t *testing.T) { - assertions := assert.New(t) - - defer setupLocalDistroForTesting()() - - expectedDiscoveredPlugins := append(expectedDiscoveredContextPlugins, expectedDiscoveredStandalonePlugins...) - discoveredPlugins, err := AvailablePlugins() - assertions.Nil(err) - assertions.Equal(len(expectedDiscoveredPlugins), len(discoveredPlugins)) - - // Install login, cluster plugins - mockInstallPlugin(assertions, "login", "v0.2.0", configtypes.TargetUnknown) - - // Considering `login` plugin with `` target is already installed and - // getting discovered through some discoveries source - // - // if the same `login` plugin is now getting discovered with `k8s` target - // verify the result of AvailablePlugins - - discoverySource := configtypes.PluginDiscovery{ - Local: &configtypes.LocalDiscovery{ - Name: "fake-with-k8s-target", - Path: "standalone-k8s-target", - }, - } - err = configlib.SetCLIDiscoverySource(discoverySource) - assertions.Nil(err) - - discoveredPlugins, err = AvailablePlugins() - assertions.Nil(err) - assertions.Equal(len(expectedDiscoveredPlugins), len(discoveredPlugins)) - - expectedInstallationStatusOfPlugins := []discovery.Discovered{ - { - Name: "login", - Target: configtypes.TargetK8s, - InstalledVersion: "v0.2.0", - Status: common.PluginStatusInstalled, - }, - } - - for i := range discoveredPlugins { - log.Infof("Discovered: %v, %v, %v, %v", discoveredPlugins[i].Name, discoveredPlugins[i].Target, discoveredPlugins[i].Status, discoveredPlugins[i].InstalledVersion) - } - - for _, eisp := range expectedInstallationStatusOfPlugins { - p := findDiscoveredPlugin(discoveredPlugins, eisp.Name, eisp.Target) - assertions.NotNil(p) - assertions.Equal(eisp.Status, p.Status, eisp.Name) - assertions.Equal(eisp.InstalledVersion, p.InstalledVersion, eisp.Name) - } -} - -func Test_AvailablePlugins_With_K8s_None_Target_Plugin_Name_Conflict_With_Plugin_Installed_But_Not_Getting_Discovered(t *testing.T) { - assertions := assert.New(t) - - defer setupLocalDistroForTesting()() - - expectedDiscoveredPlugins := append(expectedDiscoveredContextPlugins, expectedDiscoveredStandalonePlugins...) - discoveredPlugins, err := AvailablePlugins() - assertions.Nil(err) - assertions.Equal(len(expectedDiscoveredPlugins), len(discoveredPlugins)) - - // Install login, cluster plugins - mockInstallPlugin(assertions, "login", "v0.2.0", configtypes.TargetUnknown) - - // Considering `login` plugin with `` target is already installed and - // getting discovered through some discoveries source - // - // if the same `login` plugin is now getting discovered with `k8s` target - // verify the result of AvailablePlugins - - // Replace old discovery source to point to new standalone discovery where the same plugin is getting - // discovered through k8s target - discoverySource := configtypes.PluginDiscovery{ - Local: &configtypes.LocalDiscovery{ - Name: "fake", - Path: "standalone-k8s-target", - }, - } - err = configlib.SetCLIDiscoverySource(discoverySource) - assertions.Nil(err) - - discoveredPlugins, err = AvailablePlugins() - assertions.Nil(err) - assertions.Equal(len(expectedDiscoveredPlugins), len(discoveredPlugins)) - - expectedInstallationStatusOfPlugins := []discovery.Discovered{ - { - Name: "login", - Target: configtypes.TargetK8s, - InstalledVersion: "v0.2.0", - Status: common.PluginStatusInstalled, - }, - } - - for _, eisp := range expectedInstallationStatusOfPlugins { - p := findDiscoveredPlugin(discoveredPlugins, eisp.Name, eisp.Target) - assertions.NotNil(p) - assertions.Equal(eisp.Status, p.Status, eisp.Name) - assertions.Equal(eisp.InstalledVersion, p.InstalledVersion, eisp.Name) - } -} - -func Test_AvailablePlugins_From_LocalSource(t *testing.T) { - assertions := assert.New(t) - - defer setupLocalDistroForTesting()() - - currentDirAbsPath, _ := filepath.Abs(".") - discoveredPlugins, err := AvailablePluginsFromLocalSource(filepath.Join(currentDirAbsPath, "test", "local")) - assertions.Nil(err) - - expectedInstallationStatusOfPlugins := []discovery.Discovered{ - { - Name: "cluster", - Scope: common.PluginScopeStandalone, - Target: configtypes.TargetK8s, - Status: common.PluginStatusNotInstalled, - }, - { - Name: "management-cluster", - Scope: common.PluginScopeStandalone, - Target: configtypes.TargetK8s, - Status: common.PluginStatusNotInstalled, - }, - { - Name: "management-cluster", - Scope: common.PluginScopeStandalone, - Target: configtypes.TargetTMC, - Status: common.PluginStatusNotInstalled, - }, - { - Name: "login", - Scope: common.PluginScopeStandalone, - Target: configtypes.TargetK8s, - Status: common.PluginStatusNotInstalled, - }, - { - Name: "feature", - Scope: common.PluginScopeStandalone, - Target: configtypes.TargetK8s, - Status: common.PluginStatusNotInstalled, - }, - { - Name: "cluster", - Scope: common.PluginScopeStandalone, - Target: configtypes.TargetTMC, - Status: common.PluginStatusNotInstalled, - }, - { - Name: "myplugin", - Scope: common.PluginScopeStandalone, - Target: configtypes.TargetK8s, - Status: common.PluginStatusNotInstalled, - }, - { - Name: "myplugin", - Scope: common.PluginScopeStandalone, - Target: configtypes.TargetTMC, - Status: common.PluginStatusNotInstalled, - }, - } - - assertions.Equal(len(expectedInstallationStatusOfPlugins), len(discoveredPlugins)) - - for _, eisp := range expectedInstallationStatusOfPlugins { - p := findDiscoveredPlugin(discoveredPlugins, eisp.Name, eisp.Target) - assertions.NotNil(p, "plugin %q with target %q not found", eisp.Name, eisp.Target) - assertions.Equal(eisp.Status, p.Status, "status mismatch for plugin %q with target %q", eisp.Name, eisp.Target) - assertions.Equal(eisp.Scope, p.Scope, "scope mismatch for plugin %q with target %q", eisp.Name, eisp.Target) - } + groupID = testGroupName + ":" + testGroupVersion + fullGroupID, err = InstallPluginsFromGroup("cluster", groupID) + assertions.NotNil(err) + assertions.Equal(groupID, fullGroupID) + assertions.Contains(err.Error(), fmt.Sprintf("plugin 'cluster' from group '%s' is not mandatory to install", fullGroupID)) } func Test_InstallPlugin_InstalledPlugins_From_LocalSource(t *testing.T) { @@ -771,104 +515,44 @@ func Test_DeletePlugin(t *testing.T) { assertions.Contains(err.Error(), fmt.Sprintf(missingTargetStr, "myplugin")) } -func Test_ValidatePlugin(t *testing.T) { - assertions := assert.New(t) - - pd := cli.PluginInfo{} - err := ValidatePlugin(&pd) - assertions.Contains(err.Error(), "plugin name cannot be empty") - - pd.Name = "fake-plugin" - err = ValidatePlugin(&pd) - assertions.NotContains(err.Error(), "plugin name cannot be empty") - assertions.Contains(err.Error(), "plugin \"fake-plugin\" version cannot be empty") - assertions.Contains(err.Error(), "plugin \"fake-plugin\" group cannot be empty") -} - -func Test_SyncPlugins_All_Plugins_No_Central_Repo(t *testing.T) { +func Test_SyncPlugins(t *testing.T) { assertions := assert.New(t) - defer setupLocalDistroForTesting()() + defer setupPluginSourceForTesting()() execCommand = fakeInfoExecCommand defer func() { execCommand = exec.Command }() - // Turn off central repo feature - featureArray := strings.Split(constants.FeatureDisableCentralRepositoryForTesting, ".") - err := configlib.SetFeature(featureArray[1], featureArray[2], "true") - assertions.Nil(err) - - expectedDiscoveredPlugins := append(expectedDiscoveredContextPlugins, expectedDiscoveredStandalonePlugins...) - - // Get all available plugins(standalone+context-aware) and verify the status is `not installed` - discovered, err := AvailablePlugins() - assertions.Nil(err) - assertions.Equal(len(expectedDiscoveredPlugins), len(discovered)) + // Get the server plugins (they are not installed yet) + serverPlugins, err := DiscoverServerPlugins() + assertions.NotNil(err) + // There is an error for the kubernetes discovery since we don't have a cluster + // but other server plugins will be found, so we use those + assertions.Contains(err.Error(), `Failed to load Kubeconfig file from "config"`) + assertions.Equal(len(expectedDiscoveredContextPlugins), len(serverPlugins)) - for _, edp := range expectedDiscoveredPlugins { - p := findDiscoveredPlugin(discovered, edp.Name, edp.Target) + for _, edp := range expectedDiscoveredContextPlugins { + p := findDiscoveredPlugin(serverPlugins, edp.Name, edp.Target) assertions.NotNil(p) assertions.Equal(common.PluginStatusNotInstalled, p.Status) } // Sync all available plugins err = SyncPlugins() - assertions.Nil(err) + assertions.NotNil(err) + // There is an error for the kubernetes discovery since we don't have a cluster + // but other server plugins will be found, so we use those + assertions.Contains(err.Error(), `Failed to load Kubeconfig file from "config"`) - // Get all available plugins(standalone+context-aware) and verify the status is updated to `installed` - discovered, err = AvailablePlugins() + installedServerPlugins, err := pluginsupplier.GetInstalledServerPlugins() assertions.Nil(err) - assertions.Equal(len(expectedDiscoveredPlugins), len(discovered)) + assertions.Equal(len(installedServerPlugins), len(serverPlugins)) - for _, edp := range expectedDiscoveredPlugins { - p := findDiscoveredPlugin(discovered, edp.Name, edp.Target) + for _, isp := range installedServerPlugins { + p := findDiscoveredPlugin(serverPlugins, isp.Name, isp.Target) assertions.NotNil(p) - assertions.Equal(common.PluginStatusInstalled, p.Status) - assertions.Equal(edp.RecommendedVersion, p.InstalledVersion) } } -func Test_getInstalledButNotDiscoveredStandalonePlugins(t *testing.T) { - assertions := assert.New(t) - - availablePlugins := []discovery.Discovered{{Name: "fake1", DiscoveryType: "oci", RecommendedVersion: "v1.0.0", Status: common.PluginStatusInstalled}} - installedPlugin := []cli.PluginInfo{{Name: "fake2", Version: "v2.0.0", Discovery: "local"}} - - // If installed plugin is not part of available(discovered) plugins - plugins := getInstalledButNotDiscoveredStandalonePlugins(availablePlugins, installedPlugin) - assertions.Equal(len(plugins), 1) - assertions.Equal("fake2", plugins[0].Name) - assertions.Equal("v2.0.0", plugins[0].RecommendedVersion) - assertions.Equal(common.PluginStatusInstalled, plugins[0].Status) - - // If installed plugin is part of available(discovered) plugins and provided available plugin is already marked as `installed` - installedPlugin = append(installedPlugin, cli.PluginInfo{Name: "fake1", Version: "v1.0.0", Discovery: "local"}) - plugins = getInstalledButNotDiscoveredStandalonePlugins(availablePlugins, installedPlugin) - assertions.Equal(len(plugins), 1) - assertions.Equal("fake2", plugins[0].Name) - assertions.Equal("v2.0.0", plugins[0].RecommendedVersion) - assertions.Equal(common.PluginStatusInstalled, plugins[0].Status) - - // If installed plugin is part of available(discovered) plugins and provided available plugin is already marked as `not installed` - // then test the availablePlugin status gets updated to `installed` - availablePlugins[0].Status = common.PluginStatusNotInstalled - plugins = getInstalledButNotDiscoveredStandalonePlugins(availablePlugins, installedPlugin) - assertions.Equal(len(plugins), 1) - assertions.Equal("fake2", plugins[0].Name) - assertions.Equal("v2.0.0", plugins[0].RecommendedVersion) - assertions.Equal(common.PluginStatusInstalled, plugins[0].Status) - assertions.Equal(common.PluginStatusInstalled, availablePlugins[0].Status) - - // If installed plugin is part of available(discovered) plugins and versions installed is different than discovered version - availablePlugins[0].Status = common.PluginStatusNotInstalled - availablePlugins[0].RecommendedVersion = "v4.0.0" - plugins = getInstalledButNotDiscoveredStandalonePlugins(availablePlugins, installedPlugin) - assertions.Equal(len(plugins), 1) - assertions.Equal("fake2", plugins[0].Name) - assertions.Equal("v2.0.0", plugins[0].RecommendedVersion) - assertions.Equal(common.PluginStatusInstalled, plugins[0].Status) - assertions.Equal(common.PluginStatusInstalled, availablePlugins[0].Status) -} - func Test_setAvailablePluginsStatus(t *testing.T) { assertions := assert.New(t) @@ -1153,141 +837,6 @@ func TestVerifyPluginPostDownload(t *testing.T) { } } -func Test_removeDuplicates(t *testing.T) { - assertions := assert.New(t) - - tcs := []struct { - name string - inputPlugins []discovery.Discovered - expectedResult []discovery.Discovered - }{ - { - name: "when plugin name-target conflict happens with '' and 'k8s' targeted plugins ", - inputPlugins: []discovery.Discovered{ - { - Name: "foo", - Target: configtypes.TargetUnknown, - Scope: common.PluginScopeStandalone, - }, - { - Name: "foo", - Target: configtypes.TargetK8s, - Scope: common.PluginScopeStandalone, - }, - { - Name: "bar", - Target: configtypes.TargetK8s, - Scope: common.PluginScopeStandalone, - }, - }, - expectedResult: []discovery.Discovered{ - { - Name: "foo", - Target: configtypes.TargetK8s, - Scope: common.PluginScopeStandalone, - }, - { - Name: "bar", - Target: configtypes.TargetK8s, - Scope: common.PluginScopeStandalone, - }, - }, - }, - { - name: "when same plugin exists for '', 'k8s' and 'tmc' target as standalone plugin", - inputPlugins: []discovery.Discovered{ - { - Name: "foo", - Target: configtypes.TargetUnknown, - Scope: common.PluginScopeStandalone, - }, - { - Name: "foo", - Target: configtypes.TargetK8s, - Scope: common.PluginScopeStandalone, - }, - { - Name: "foo", - Target: configtypes.TargetTMC, - Scope: common.PluginScopeStandalone, - }, - }, - expectedResult: []discovery.Discovered{ - { - Name: "foo", - Target: configtypes.TargetK8s, - Scope: common.PluginScopeStandalone, - }, - { - Name: "foo", - Target: configtypes.TargetTMC, - Scope: common.PluginScopeStandalone, - }, - }, - }, - { - name: "when foo standalone plugin is available with `k8s` and `` target and also available as context-scoped plugin with `k8s` target", - inputPlugins: []discovery.Discovered{ - { - Name: "foo", - Target: configtypes.TargetUnknown, - Scope: common.PluginScopeStandalone, - }, - { - Name: "foo", - Target: configtypes.TargetK8s, - Scope: common.PluginScopeStandalone, - }, - { - Name: "foo", - Target: configtypes.TargetK8s, - Scope: common.PluginScopeContext, - }, - }, - expectedResult: []discovery.Discovered{ - { - Name: "foo", - Target: configtypes.TargetK8s, - Scope: common.PluginScopeContext, - }, - }, - }, - { - name: "when tmc targeted plugin exists as standalone as well as context-scope", - inputPlugins: []discovery.Discovered{ - { - Name: "foo", - Target: configtypes.TargetTMC, - Scope: common.PluginScopeStandalone, - }, - { - Name: "foo", - Target: configtypes.TargetTMC, - Scope: common.PluginScopeContext, - }, - }, - expectedResult: []discovery.Discovered{ - { - Name: "foo", - Target: configtypes.TargetTMC, - Scope: common.PluginScopeContext, - }, - }, - }, - } - - for _, tc := range tcs { - t.Run(tc.name, func(t *testing.T) { - result := combineDuplicatePlugins(tc.inputPlugins) - assertions.Equal(len(result), len(tc.expectedResult)) - for i := range tc.expectedResult { - p := findDiscoveredPlugin(result, tc.expectedResult[i].Name, tc.expectedResult[i].Target) - assertions.Equal(p.Scope, tc.expectedResult[i].Scope) - } - }) - } -} - func TestHelperProcess(t *testing.T) { if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" { return @@ -1409,17 +958,6 @@ func TestGetPluginDiscoveries(t *testing.T) { assertions.Equal(expectedTestDiscoveries[2], discoveries[4].OCI.Image) assertions.Equal(expectedTestDiscoveries[3], discoveries[5].OCI.Image) - // Test with the Central Repo feature disabled - featureArray := strings.Split(constants.FeatureDisableCentralRepositoryForTesting, ".") - err = configlib.SetFeature(featureArray[1], featureArray[2], "true") - assertions.Nil(err) - - discoveries, err = getPluginDiscoveries() - assertions.Nil(err) - assertions.Equal(2, len(discoveries)) - assertions.Equal("default-local", discoveries[0].Local.Name) - assertions.Equal("fake", discoveries[1].Local.Name) - os.Unsetenv(constants.ConfigVariableAdditionalDiscoveryForTesting) } diff --git a/pkg/pluginmanager/test/config-ng.yaml b/pkg/pluginmanager/test/config-ng.yaml index 9f597f2cf..91ed17a5e 100644 --- a/pkg/pluginmanager/test/config-ng.yaml +++ b/pkg/pluginmanager/test/config-ng.yaml @@ -6,6 +6,8 @@ cli: - local: name: fake path: standalone + eulaStatus: accepted + ceipOptIn: "false" currentContext: kubernetes: mgmt mission-control: tmc-fake diff --git a/pkg/pluginmanager/test/config-ng2.yaml b/pkg/pluginmanager/test/config-ng2.yaml new file mode 100644 index 000000000..5e0f9c519 --- /dev/null +++ b/pkg/pluginmanager/test/config-ng2.yaml @@ -0,0 +1,28 @@ +cli: + discoverySources: + - oci: + name: default + image: example.com/plugin-inventory:latest + eulaStatus: accepted + ceipOptIn: "false" +currentContext: + kubernetes: mgmt + mission-control: tmc-fake +contexts: + - clusterOpts: + context: mgmt-admin@mgmt + path: config + isManagementCluster: true + name: mgmt + target: kubernetes + discoverySources: + - local: + name: fake-mgmt + path: context-mgmt + - globalOpts: + name: tmc-fake + target: mission-control + discoverySources: + - local: + name: fake-tmc + path: context-tmc diff --git a/pkg/pluginmanager/test/config.yaml b/pkg/pluginmanager/test/config.yaml index c2ecbd624..37b007731 100644 --- a/pkg/pluginmanager/test/config.yaml +++ b/pkg/pluginmanager/test/config.yaml @@ -1,36 +1,26 @@ -apiVersion: config.tanzu.vmware.com/v1alpha1 -current: mgmt -currentContext: - kubernetes: mgmt - mission-control: tmc-fake -kind: ClientConfig -metadata: - creationTimestamp: null +clientOptions: + features: + global: + context-target-v2: "true" + cli: + edition: tkg + bomRepo: projects.registry.vmware.com/tkg + compatibilityFilePath: tkg-compatibility servers: - managementClusterOpts: context: mgmt-admin@mgmt path: config name: mgmt - type: global + type: managementcluster discoverySources: - local: name: fake-mgmt path: context-mgmt -contexts: - - clusterOpts: - context: mgmt-admin@mgmt - path: config - isManagementCluster: true - name: mgmt - target: kubernetes - discoverySources: - - local: - name: fake-mgmt - path: context-mgmt - - globalOpts: - name: tmc-fake - target: mission-control + - name: tmc-fake + type: global + globalOpts: discoverySources: - local: name: fake-tmc path: context-tmc +current: mgmt