diff --git a/docs/quickstart/install.md b/docs/quickstart/install.md index a039f7d24..6a605a2c5 100644 --- a/docs/quickstart/install.md +++ b/docs/quickstart/install.md @@ -414,10 +414,10 @@ resulting images without authentication. To download plugins you will use the `tanzu plugin download-bundle` command and specify the different plugin groups or plugins relevant to your environment. -This command will download the plugin bundle containing specified plugins and -the plugin versions specified in the plugin group definition. The bundle will -also include the plugin group definition itself if specified, so that it can be -used for plugin installation by users. +This command will download the plugin bundle containing the specified plugin +versions as well as the plugin versions specified in the plugin group definition. +The bundle will also include the plugin group definition itself if specified, +so that it can be used for plugin installation by users. Note that the latest version of the `vmware-tanzucli/essentials` plugin group and the plugin versions it contains will automatically be included in any plugin @@ -449,21 +449,21 @@ tanzu plugin download-bundle --group vmware-tkg/default --to-tar /tmp/plugin_bun If you want to download a specific plugin, the `--plugin` flag can be used. Using the `--plugin` flag is for cases where a plugin is not part of a plugin group, -but that normally using `--group` is the recommended approach. +however, when possible, using `--group` is the recommended approach. Below are the supported formats for the `--plugin` flag: ```sh ---plugin name : Downloads the latest available version of the plugin for all matching targets. ---plugin name:version : Downloads the specified version of the plugin for all matching targets. Use 'latest' as version for latest available version ---plugin name@target:version : Downloads the specified version of the plugin for the specified target. Use 'latest' as version for latest available version +--plugin name : Downloads the latest available version of the plugin. (Returns an error if the specified plugin name is available across multiple targets) +--plugin name:version : Downloads the specified version of the plugin. (Returns an error if the specified plugin name is available across multiple targets) +--plugin name@target:version : Downloads the specified version of the plugin for the specified target. --plugin name@target : Downloads the latest available version of the plugin for the specified target. ``` ```sh -# To download plugin bundle with all available versions 'cluster' plugin across all targets +# To download plugin bundle with the latest available version of the 'cluster' plugin. (Returns an error if the specified plugin name is available across multiple targets) tanzu plugin download-bundle --plugin cluster --to-tar /tmp/plugin_bundle_cluster.tar.gz -# To download plugin bundle with all available versions 'cluster' plugin for `kubernetes` target +# To download plugin bundle with the latest available version of the 'cluster' plugin for `kubernetes` target tanzu plugin download-bundle --plugin cluster@kubernetes --to-tar /tmp/plugin_bundle_cluster.tar.gz # To download plugin bundle with v1.0.0 version of 'cluster' plugin for `kubernetes` target @@ -473,7 +473,7 @@ tanzu plugin download-bundle --plugin cluster@kubernetes:v1.0.0 --to-tar /tmp/pl tanzu plugin download-bundle --plugin cluster@kubernetes:latest --to-tar /tmp/plugin_bundle_cluster.tar.gz ``` -Using `--group` and `--plugin` flag together are also supported and if specified the union of all the +Using the `--group` and `--plugin` flags together is also supported. In such a case the union of all the plugins and plugin-groups will be downloaded. To migrate plugins from a specific plugin repository and not use the default diff --git a/pkg/airgapped/plugin_bundle_download.go b/pkg/airgapped/plugin_bundle_download.go index c208047e0..a7d4a9756 100644 --- a/pkg/airgapped/plugin_bundle_download.go +++ b/pkg/airgapped/plugin_bundle_download.go @@ -194,11 +194,12 @@ func (o *DownloadPluginBundleOptions) getSelectedPluginInfo() ([]*plugininventor func (o *DownloadPluginBundleOptions) getPluginFromPluginID(pluginID string, pi plugininventory.PluginInventory) ([]*plugininventory.PluginInventoryEntry, error) { pluginName, pluginTarget, pluginVersion := utils.ParsePluginID(pluginID) if pluginVersion == "" { - pluginVersion = "latest" + pluginVersion = cli.VersionLatest } + pluginEntries, err := pi.GetPlugins(&plugininventory.PluginInventoryFilter{ Name: pluginName, - Target: configtypes.Target(pluginTarget), + Target: configtypes.StringToTarget(pluginTarget), Version: pluginVersion, IncludeHidden: true, }) // Include the hidden plugins during plugin migration diff --git a/pkg/command/plugin_bundle.go b/pkg/command/plugin_bundle.go index 82059d092..7629b8293 100644 --- a/pkg/command/plugin_bundle.go +++ b/pkg/command/plugin_bundle.go @@ -45,10 +45,10 @@ to an internet-restricted environment. Please also see the "upload-bundle" comma # Download a plugin bundle for a specific group version from the default discovery source tanzu plugin download-bundle --group vmware-tkg/default:v1.0.0 --to-tar /tmp/plugin_bundle_vmware_tkg_default_v1.0.0.tar.gz - # To download plugin bundle with specific plugin from the default discovery source - # --plugin name : Downloads the latest available version of the plugin for all matching targets. - # --plugin name:version : Downloads the specified version of the plugin for all matching targets. Use 'latest' as version for latest available version - # --plugin name@target:version : Downloads the specified version of the plugin for the specified target. Use 'latest' as version for latest available version + # To download plugin bundle with a specific plugin from the default discovery source + # --plugin name : Downloads the latest available version of the plugin. (Returns an error if the specified plugin name is available across multiple targets) + # --plugin name:version : Downloads the specified version of the plugin. (Returns an error if the specified plugin name is available across multiple targets) + # --plugin name@target:version : Downloads the specified version of the plugin for the specified target. # --plugin name@target : Downloads the latest available version of the plugin for the specified target. tanzu plugin download-bundle --plugin cluster:v1.0.0 --to-tar /tmp/plugin_bundle_cluster.tar.gz @@ -164,6 +164,30 @@ func completeUploadBundle(_ *cobra.Command, _ []string, _ string) ([]string, cob return activeHelpNoMoreArgs(nil), cobra.ShellCompDirectiveNoFileComp } +func completionDownloadInventoryImage() (string, error) { + // For a download-bundle, we cannot use the DB cache. This is because + // the download-bundle does not use the configured plugin sources. Instead it + // uses the repo specified by the `--image`` flag, or, without the `--image` flag, + // it uses the default central repo automatically. + + // We start by downloading the inventory of the required repo. This is not + // very fast, but there isn't much we can do about it. + + var err error + tempDBDir, err := os.MkdirTemp("", "") + if err != nil { + return "", err + } + + // Download the plugin inventory oci image to tempDBDir + inventoryFile := filepath.Join(tempDBDir, plugininventory.SQliteDBFileName) + if err := imageProcessorForDownloadBundleComp.DownloadImageAndSaveFilesToDir(dpbo.pluginDiscoveryOCIImage, filepath.Dir(inventoryFile)); err != nil { + return "", err + } + + return inventoryFile, nil +} + func completeGroupVersionsForDownloadBundle(groups []*plugininventory.PluginGroup, id, _ string) []string { var group *plugininventory.PluginGroup for _, g := range groups { @@ -195,30 +219,14 @@ func completeGroupVersionsForDownloadBundle(groups []*plugininventory.PluginGrou } func completionGetPluginGroupsForBundleDownload() ([]*plugininventory.PluginGroup, error) { - // For a download-bundle, we cannot use the DB cache. This is because - // the download-bundle does not use the configured plugin sources. Instead it - // uses the repo specified by the `--image`` flag, or, without the `--image` flag, - // it uses the default central repo automatically. - - // We start by downloading the inventory of the required repo. This is not - // very fast, but there isn't much we can do about it. - - var err error - tempDBDir, err := os.MkdirTemp("", "") + inventoryFile, err := completionDownloadInventoryImage() + defer os.RemoveAll(inventoryFile) if err != nil { return nil, err } - defer os.RemoveAll(tempDBDir) - - // Download the plugin inventory oci image to tempDBDir - repoImage := dpbo.pluginDiscoveryOCIImage - inventoryFile := filepath.Join(tempDBDir, plugininventory.SQliteDBFileName) - if err := imageProcessorForDownloadBundleComp.DownloadImageAndSaveFilesToDir(repoImage, filepath.Dir(inventoryFile)); err != nil { - return nil, err - } // Read the plugin inventory database to read the plugin groups it contains - pi := plugininventory.NewSQLiteInventory(inventoryFile, path.Dir(repoImage)) + pi := plugininventory.NewSQLiteInventory(inventoryFile, path.Dir(dpbo.pluginDiscoveryOCIImage)) pluginGroups, err := pi.GetPluginGroups(plugininventory.PluginGroupFilter{IncludeHidden: true}) // Include the hidden plugin groups during plugin migration if err != nil { return nil, err @@ -226,7 +234,7 @@ func completionGetPluginGroupsForBundleDownload() ([]*plugininventory.PluginGrou return pluginGroups, err } -func completeGroupsAndVersionForBundleDownload(_ *cobra.Command, _ []string, toComplete string) ([]string, cobra.ShellCompDirective) { +func completeGroupsAndVersionForBundleDownload(_ *cobra.Command, _ []string, toComplete string) ([]string, cobra.ShellCompDirective) { //nolint:dupl pluginGroups, err := completionGetPluginGroupsForBundleDownload() if err != nil { return nil, cobra.ShellCompDirectiveNoFileComp @@ -295,30 +303,14 @@ func completeVersionInPluginIDForDownloadBundle(plugins []*plugininventory.Plugi } func completionGetPluginsForBundleDownload() ([]*plugininventory.PluginInventoryEntry, error) { - // For a download-bundle, we cannot use the DB cache. This is because - // the download-bundle does not use the configured plugin sources. Instead it - // uses the repo specified by the `--image`` flag, or, without the `--image` flag, - // it uses the default central repo automatically. - - // We start by downloading the inventory of the required repo. This is not - // very fast, but there isn't much we can do about it. - - var err error - tempDBDir, err := os.MkdirTemp("", "") + inventoryFile, err := completionDownloadInventoryImage() + defer os.RemoveAll(inventoryFile) if err != nil { return nil, err } - defer os.RemoveAll(tempDBDir) - - // Download the plugin inventory oci image to tempDBDir - repoImage := dpbo.pluginDiscoveryOCIImage - inventoryFile := filepath.Join(tempDBDir, plugininventory.SQliteDBFileName) - if err := imageProcessorForDownloadBundleComp.DownloadImageAndSaveFilesToDir(repoImage, filepath.Dir(inventoryFile)); err != nil { - return nil, err - } - // Read the plugin inventory database to read the plugin groups it contains - pi := plugininventory.NewSQLiteInventory(inventoryFile, path.Dir(repoImage)) + // Read the plugin inventory database to read the plugins it contains + pi := plugininventory.NewSQLiteInventory(inventoryFile, path.Dir(dpbo.pluginDiscoveryOCIImage)) pluginEntries, err := pi.GetPlugins(&plugininventory.PluginInventoryFilter{IncludeHidden: true}) // Include the hidden plugin groups during plugin migration if err != nil { return nil, err @@ -326,45 +318,38 @@ func completionGetPluginsForBundleDownload() ([]*plugininventory.PluginInventory return pluginEntries, err } -func completePluginIDForBundleDownload(_ *cobra.Command, _ []string, toComplete string) ([]string, cobra.ShellCompDirective) { - PluginEntries, err := completionGetPluginsForBundleDownload() +func completePluginIDForBundleDownload(_ *cobra.Command, _ []string, toComplete string) ([]string, cobra.ShellCompDirective) { //nolint:dupl + pluginEntries, err := completionGetPluginsForBundleDownload() if err != nil { return nil, cobra.ShellCompDirectiveNoFileComp } - if PluginEntries == nil { + if pluginEntries == nil { comps := cobra.AppendActiveHelp(nil, fmt.Sprintf("There are no plugins in %s", dpbo.pluginDiscoveryOCIImage)) return comps, cobra.ShellCompDirectiveNoFileComp } if idx := strings.Index(toComplete, ":"); idx != -1 { // The pluginID is already specified before the : - // so now we should complete the group version. + // so now we should complete the plugin version. // Since more recent versions are more likely to be // useful, we tell the shell to preserve the order // using cobra.ShellCompDirectiveKeepOrder pluginID := toComplete[:idx] versionToComplete := toComplete[idx+1:] - return completeVersionInPluginIDForDownloadBundle(PluginEntries, pluginID, versionToComplete), cobra.ShellCompDirectiveNoFileComp | cobra.ShellCompDirectiveKeepOrder + return completeVersionInPluginIDForDownloadBundle(pluginEntries, pluginID, versionToComplete), cobra.ShellCompDirectiveNoFileComp | cobra.ShellCompDirectiveKeepOrder } - // Complete plugin group names + // Complete pluginIDs var comps []string - for _, p := range PluginEntries { - id := plugininventory.PluginToID(p) - if strings.HasPrefix(id, toComplete) { - comps = append(comps, id) - } - } - - if len(comps) == 0 { - return cobra.AppendActiveHelp(nil, fmt.Sprintf("There are no plugins matching: '%s'", toComplete)), cobra.ShellCompDirectiveNoFileComp | cobra.ShellCompDirectiveKeepOrder + for _, p := range pluginEntries { + comps = append(comps, fmt.Sprintf("%s\t%s", plugininventory.PluginToID(p), p.Description)) } // Sort to allow for testing sort.Strings(comps) - // Don't add a space after the group name so the uer can add a : if + // Don't add a space after the pluginID so the uer can add a : if // they want to specify a version. return comps, cobra.ShellCompDirectiveNoFileComp | cobra.ShellCompDirectiveNoSpace } diff --git a/pkg/command/plugin_bundle_test.go b/pkg/command/plugin_bundle_test.go index dd62c8285..15c3a314d 100644 --- a/pkg/command/plugin_bundle_test.go +++ b/pkg/command/plugin_bundle_test.go @@ -130,25 +130,15 @@ func TestCompletionPluginBundle(t *testing.T) { // This command should trigger downloading an OCI plugin inventory image imageMustBeDownloaded: true, // ":6" is the value of the ShellCompDirectiveNoFileComp | ShellCompDirectiveNoSpace - expected: "cluster@kubernetes\n" + - "cluster@mission-control\n" + - "feature@kubernetes\n" + - "isolated-cluster@global\n" + - "login@global\n" + - "management-cluster@kubernetes\n" + - "management-cluster@mission-control\n" + - "package@kubernetes\n" + - "secret@kubernetes\n" + - ":6\n", - }, - { - test: "completion for the --plugin flag value for the plugin name part with partial name specified of the download-bundle command", - args: []string{"__complete", "plugin", "download-bundle", "--plugin", "clu"}, - // This command should trigger downloading an OCI plugin inventory image - imageMustBeDownloaded: true, - // ":6" is the value of the ShellCompDirectiveNoFileComp | ShellCompDirectiveNoSpace - expected: "cluster@kubernetes\n" + - "cluster@mission-control\n" + + expected: "cluster@kubernetes\tPlugin cluster/kubernetes description\n" + + "cluster@mission-control\tPlugin cluster/mission-control description\n" + + "feature@kubernetes\tPlugin feature/kubernetes description\n" + + "isolated-cluster@global\tPlugin isolated-cluster/global description\n" + + "login@global\tPlugin login/global description\n" + + "management-cluster@kubernetes\tPlugin management-cluster/kubernetes description\n" + + "management-cluster@mission-control\tPlugin management-cluster/mission-control description\n" + + "package@kubernetes\tPlugin package/kubernetes description\n" + + "secret@kubernetes\tPlugin secret/kubernetes description\n" + ":6\n", }, { @@ -170,15 +160,6 @@ func TestCompletionPluginBundle(t *testing.T) { expected: "_activeHelp_ There are no plugins matching: 'invalid'\n" + ":36\n", }, - { - test: "completion for the --plugin flag value for the plugin name of an invalid partial plugin name for the download-bundle command", - args: []string{"__complete", "plugin", "download-bundle", "--plugin", "invalid"}, - // This command should trigger downloading an OCI plugin inventory image - imageMustBeDownloaded: true, - // ":36" is the value of the ShellCompDirectiveNoFileComp | ShellCompDirectiveKeepOrder - expected: "_activeHelp_ There are no plugins matching: 'invalid'\n" + - ":36\n", - }, // ============================ // tanzu plugin upload-bundle