From f48bbb5b8e31b8fd97b701e1a59e51fa14f49af0 Mon Sep 17 00:00:00 2001 From: Anuj Chaudhari Date: Wed, 10 Jul 2024 15:54:12 -0700 Subject: [PATCH 1/2] Support activating plugins on plugin group publish --- pkg/constants/env_variables.go | 4 + pkg/plugininventory/sqlite_inventory.go | 57 +++++++-- pkg/plugininventory/sqlite_inventory_test.go | 124 +++++++++++++++++-- 3 files changed, 164 insertions(+), 21 deletions(-) diff --git a/pkg/constants/env_variables.go b/pkg/constants/env_variables.go index e65a5399f..1dbe993c0 100644 --- a/pkg/constants/env_variables.go +++ b/pkg/constants/env_variables.go @@ -87,4 +87,8 @@ const ( // UseStableKubeContextNameForTanzuContext uses the stable kube context name associated with tanzu context. // CLI would not change the context name when the TAP resource pointed by the CLI context is changed. UseStableKubeContextNameForTanzuContext = "TANZU_CLI_USE_STABLE_KUBE_CONTEXT_NAME" + + // ActivatePluginsOnPluginGroupPublish activates all the plugins specified within the plugin group + // as part of the plugin group publishing + ActivatePluginsOnPluginGroupPublish = "TANZU_CLI_ACTIVATE_PLUGINS_ON_PLUGIN_GROUP_PUBLISH" ) diff --git a/pkg/plugininventory/sqlite_inventory.go b/pkg/plugininventory/sqlite_inventory.go index 904229b55..8e9cf4209 100644 --- a/pkg/plugininventory/sqlite_inventory.go +++ b/pkg/plugininventory/sqlite_inventory.go @@ -645,7 +645,7 @@ func (b *SQLiteInventory) InsertPlugin(pluginInventoryEntry *PluginInventoryEntr // InsertPluginGroup inserts plugin-group to the inventory // specifying override will delete the existing plugin-group and add new one -func (b *SQLiteInventory) InsertPluginGroup(pg *PluginGroup, override bool) error { +func (b *SQLiteInventory) InsertPluginGroup(pg *PluginGroup, override bool) error { //nolint:gocyclo db, err := sql.Open("sqlite", b.inventoryFile) if err != nil { return errors.Wrapf(err, "failed to open the DB from '%s' file", b.inventoryFile) @@ -674,7 +674,12 @@ func (b *SQLiteInventory) InsertPluginGroup(pg *PluginGroup, override bool) erro } } - allowHiddenPlugins, _ := strconv.ParseBool(os.Getenv(constants.ConfigVariableIncludeDeactivatedPluginsForTesting)) + includeDeactivatedPluginsForTesting, _ := strconv.ParseBool(os.Getenv(constants.ConfigVariableIncludeDeactivatedPluginsForTesting)) + activatePlugins, _ := strconv.ParseBool(os.Getenv(constants.ActivatePluginsOnPluginGroupPublish)) + + // Allow hidden plugins if either of the below configuration is specified + allowHiddenPlugins := includeDeactivatedPluginsForTesting || activatePlugins + for version, plugins := range pg.Versions { for _, pi := range plugins { // Skip plugin group verification. If TANZU_CLI_SKIP_PLUGIN_GROUP_VERIFICATION_ON_PUBLISH is set while publishing a plugin-group @@ -692,6 +697,16 @@ func (b *SQLiteInventory) InsertPluginGroup(pg *PluginGroup, override bool) erro } } + // Activate plugins on plugin group publish if the TANZU_CLI_ACTIVATE_PLUGINS_ON_PLUGIN_GROUP_PUBLISH + // environment variable is set to True. + // Note: If it is set to false, plugins won't be deactivated + if activatePlugins { + err = b.updatePluginActivationState(db, pi.Name, string(pi.Target), pi.Version, true) + if err != nil { + return errors.Wrap(err, "unable to activate plugin with in plugin group") + } + } + row := groupDBRow{ vendor: pg.Vendor, publisher: pg.Publisher, @@ -724,18 +739,25 @@ func (b *SQLiteInventory) UpdatePluginActivationState(pluginInventoryEntry *Plug defer db.Close() for version := range pluginInventoryEntry.Artifacts { - result, err := db.Exec("UPDATE PluginBinaries SET hidden = ? WHERE PluginName = ? AND Target = ? AND Version = ? AND Publisher = ? AND Vendor = ? ;", strconv.FormatBool(pluginInventoryEntry.Hidden), pluginInventoryEntry.Name, string(pluginInventoryEntry.Target), version, pluginInventoryEntry.Publisher, pluginInventoryEntry.Vendor) + err := b.updatePluginActivationState(db, pluginInventoryEntry.Name, string(pluginInventoryEntry.Target), version, !pluginInventoryEntry.Hidden) if err != nil { - return errors.Wrapf(err, "unable to update plugin %v_%v", pluginInventoryEntry.Name, string(pluginInventoryEntry.Target)) + return err } - rowsAffected, _ := result.RowsAffected() - if rowsAffected == 0 { - return errors.Errorf("unable to update plugin %v_%v", pluginInventoryEntry.Name, string(pluginInventoryEntry.Target)) - } - // Write sql statement logs if required - writeSQLStatementLogs(fmt.Sprintf("UPDATE PluginBinaries SET hidden = %v WHERE PluginName = %v AND Target = %v AND Version = %v AND Publisher = %v AND Vendor = %v ;\n", strconv.FormatBool(pluginInventoryEntry.Hidden), pluginInventoryEntry.Name, string(pluginInventoryEntry.Target), version, pluginInventoryEntry.Publisher, pluginInventoryEntry.Vendor)) } + return nil +} +func (b *SQLiteInventory) updatePluginActivationState(db *sql.DB, name, target, version string, activate bool) error { + result, err := db.Exec("UPDATE PluginBinaries SET hidden = ? WHERE PluginName = ? AND Target = ? AND Version = ? ;", strconv.FormatBool(!activate), name, target, version) + if err != nil { + return errors.Wrapf(err, "unable to update plugin %v_%v", name, target) + } + rowsAffected, _ := result.RowsAffected() + if rowsAffected == 0 { + return errors.Errorf("unable to update plugin %v_%v", name, target) + } + // Write sql statement logs if required + writeSQLStatementLogs(fmt.Sprintf("UPDATE PluginBinaries SET hidden = %v WHERE PluginName = %v AND Target = %v AND Version = %v ;\n", strconv.FormatBool(!activate), name, target, version)) return nil } @@ -746,7 +768,20 @@ func (b *SQLiteInventory) UpdatePluginGroupActivationState(pg *PluginGroup) erro } defer db.Close() - for version := range pg.Versions { + activatePlugins, _ := strconv.ParseBool(os.Getenv(constants.ActivatePluginsOnPluginGroupPublish)) + + for version, plugins := range pg.Versions { + // Activate plugins on plugin group activate if the TANZU_CLI_ACTIVATE_PLUGINS_ON_PLUGIN_GROUP_PUBLISH + // environment variable is set to `True` and we are trying to activate the plugin group + if activatePlugins && !pg.Hidden { + for _, pi := range plugins { + err = b.updatePluginActivationState(db, pi.Name, string(pi.Target), pi.Version, true) + if err != nil { + return errors.Wrap(err, "unable to activate plugin with in plugin group") + } + } + } + result, err := db.Exec("UPDATE PluginGroups SET hidden = ? WHERE GroupName = ? AND Publisher = ? AND Vendor = ? AND GroupVersion = ? ;", strconv.FormatBool(pg.Hidden), pg.Name, pg.Publisher, pg.Vendor, version) if err != nil { return errors.Wrapf(err, "unable to update plugin-group '%s:%s'", PluginGroupToID(pg), version) diff --git a/pkg/plugininventory/sqlite_inventory_test.go b/pkg/plugininventory/sqlite_inventory_test.go index 9ad39db95..0ab49d34f 100644 --- a/pkg/plugininventory/sqlite_inventory_test.go +++ b/pkg/plugininventory/sqlite_inventory_test.go @@ -1486,6 +1486,44 @@ var _ = Describe("Unit tests for plugin inventory", func() { Expect(plugins[0].Version).To(Equal(groupWithHiddenPlugin.Versions["v1.0.0"][0].Version)) Expect(plugins[0].Mandatory).To(Equal(groupWithHiddenPlugin.Versions["v1.0.0"][0].Mandatory)) }) + It("should not return error if TANZU_CLI_ACTIVATE_PLUGINS_ON_PLUGIN_GROUP_PUBLISH=true and Plugins should be activated", func() { + err = os.Setenv(constants.ActivatePluginsOnPluginGroupPublish, "true") + defer os.Unsetenv(constants.ActivatePluginsOnPluginGroupPublish) + Expect(err).To(BeNil()) + + err = inventory.InsertPluginGroup(&groupWithHiddenPlugin, false) + Expect(err).To(BeNil()) + + groups, err := inventory.GetPluginGroups(PluginGroupFilter{}) + Expect(err).ToNot(HaveOccurred()) + Expect(len(groups)).To(Equal(1)) + pg := groups[0] + Expect(pg.Name).To(Equal(groupWithHiddenPlugin.Name)) + Expect(pg.Vendor).To(Equal(groupWithHiddenPlugin.Vendor)) + Expect(pg.Publisher).To(Equal(groupWithHiddenPlugin.Publisher)) + Expect(pg.Description).To(Equal(groupWithHiddenPlugin.Description)) + + Expect(pg.Hidden).To(Equal(groupWithHiddenPlugin.Hidden)) + + Expect(len(pg.Versions)).To(Equal(1)) + + plugins := pg.Versions["v1.0.0"] + Expect(len(plugins)).To(Equal(1)) + Expect(plugins[0].Name).To(Equal(groupWithHiddenPlugin.Versions["v1.0.0"][0].Name)) + Expect(plugins[0].Target).To(Equal(groupWithHiddenPlugin.Versions["v1.0.0"][0].Target)) + Expect(plugins[0].Version).To(Equal(groupWithHiddenPlugin.Versions["v1.0.0"][0].Version)) + Expect(plugins[0].Mandatory).To(Equal(groupWithHiddenPlugin.Versions["v1.0.0"][0].Mandatory)) + + // Try to get the plugin with IncludeHidden:false filter and verify that + // plugin that was deactivated before creating plugin group is now activated + updatedPlugins, err := inventory.GetPlugins(&PluginInventoryFilter{Name: plugins[0].Name, Target: plugins[0].Target, Version: plugins[0].Version, IncludeHidden: false}) + Expect(err).ToNot(HaveOccurred()) + Expect(len(updatedPlugins)).To(Equal(1)) + Expect(updatedPlugins[0].Name).To(Equal(plugins[0].Name)) + Expect(updatedPlugins[0].Target).To(Equal(plugins[0].Target)) + Expect(updatedPlugins[0].RecommendedVersion).To(Equal(plugins[0].Version)) + Expect(updatedPlugins[0].Hidden).To(BeFalse()) + }) }) Context("When inserting a plugin-group which already exists in the database", func() { BeforeEach(func() { @@ -1581,6 +1619,8 @@ var _ = Describe("Unit tests for plugin inventory", func() { Expect(err).To(BeNil(), "failed to insert plugin2") err = inventory.InsertPlugin(&piEntry3) Expect(err).To(BeNil(), "failed to insert plugin3") + err = inventory.InsertPlugin(&hiddenPluginEntry) + Expect(err).To(BeNil(), "failed to insert hidden-plugin") }) AfterEach(func() { os.RemoveAll(tmpDir) @@ -1591,7 +1631,7 @@ var _ = Describe("Unit tests for plugin inventory", func() { err = inventory.InsertPluginGroup(&pluginGroup1, false) Expect(err).To(BeNil()) }) - It("should not return error when no change has been done to the activation state and the GetPluginGroups should reflect the same", func() { + It("should not return error when no change has been done to the activation state and plugin group should still be active and the GetPluginGroups should reflect the same", func() { err = inventory.UpdatePluginGroupActivationState(&pluginGroup1) Expect(err).To(BeNil()) @@ -1608,8 +1648,35 @@ var _ = Describe("Unit tests for plugin inventory", func() { Expect(len(groups[0].Versions["v2.0.0"])).To(Equal(len(pluginGroup1.Versions["v2.0.0"]))) Expect(len(groups[0].Versions["v1.0.0"])).To(Equal(len(pluginGroup1.Versions["v1.0.0"]))) }) - It("should not return error when the activation state has been updated and the GetPluginGroups should reflect the change", func() { + It("should not return error when the plugin group is deactivated and the GetPluginGroups should not return the plugin group", func() { pluginGroupUpdated := pluginGroup1 + pluginGroupUpdated.Hidden = true + err = inventory.UpdatePluginGroupActivationState(&pluginGroupUpdated) + Expect(err).To(BeNil()) + + // Verify the result using GetPluginGroups + groups, err := inventory.GetPluginGroups(PluginGroupFilter{}) + Expect(err).ToNot(HaveOccurred()) + Expect(len(groups)).To(Equal(0)) + }) + }) + + Context("When updating the activation state of a plugin-group wrt TANZU_CLI_ACTIVATE_PLUGINS_ON_PLUGIN_GROUP_PUBLISH env variable", func() { + BeforeEach(func() { + err = os.Setenv(constants.ConfigVariableIncludeDeactivatedPluginsForTesting, "true") + defer os.Unsetenv(constants.ConfigVariableIncludeDeactivatedPluginsForTesting) + hiddenGroupWithHiddenPlugin := groupWithHiddenPlugin + hiddenGroupWithHiddenPlugin.Hidden = true + Expect(err).To(BeNil()) + err = inventory.InsertPluginGroup(&hiddenGroupWithHiddenPlugin, false) + Expect(err).To(BeNil()) + }) + It("when activating plugin group containing a deactivated plugin with TANZU_CLI_ACTIVATE_PLUGINS_ON_PLUGIN_GROUP_PUBLISH=true set, it should activate the deactivated plugin", func() { + err = os.Setenv(constants.ActivatePluginsOnPluginGroupPublish, "true") + defer os.Unsetenv(constants.ActivatePluginsOnPluginGroupPublish) + Expect(err).To(BeNil()) + + pluginGroupUpdated := groupWithHiddenPlugin pluginGroupUpdated.Hidden = false err = inventory.UpdatePluginGroupActivationState(&pluginGroupUpdated) Expect(err).To(BeNil()) @@ -1618,14 +1685,51 @@ var _ = Describe("Unit tests for plugin inventory", func() { groups, err := inventory.GetPluginGroups(PluginGroupFilter{}) Expect(err).ToNot(HaveOccurred()) Expect(len(groups)).To(Equal(1)) - Expect(groups[0].Name).To(Equal(pluginGroupUpdated.Name)) - Expect(groups[0].Vendor).To(Equal(pluginGroupUpdated.Vendor)) - Expect(groups[0].Publisher).To(Equal(pluginGroupUpdated.Publisher)) - Expect(groups[0].Description).To(Equal(pluginGroupUpdated.Description)) - Expect(groups[0].Hidden).To(Equal(pluginGroupUpdated.Hidden)) - Expect(len(groups[0].Versions)).To(Equal(len(pluginGroup1.Versions))) - Expect(len(groups[0].Versions["v2.0.0"])).To(Equal(len(pluginGroup1.Versions["v2.0.0"]))) - Expect(len(groups[0].Versions["v1.0.0"])).To(Equal(len(pluginGroup1.Versions["v1.0.0"]))) + pg := groups[0] + // Make sure the hidden field is set to correct value we requested + Expect(pg.Hidden).To(Equal(groupWithHiddenPlugin.Hidden)) + Expect(len(pg.Versions)).To(Equal(1)) + + plugins := pg.Versions["v1.0.0"] + Expect(len(plugins)).To(Equal(1)) + Expect(plugins[0].Name).To(Equal(groupWithHiddenPlugin.Versions["v1.0.0"][0].Name)) + Expect(plugins[0].Target).To(Equal(groupWithHiddenPlugin.Versions["v1.0.0"][0].Target)) + Expect(plugins[0].Version).To(Equal(groupWithHiddenPlugin.Versions["v1.0.0"][0].Version)) + Expect(plugins[0].Mandatory).To(Equal(groupWithHiddenPlugin.Versions["v1.0.0"][0].Mandatory)) + + // Try to get the plugin with IncludeHidden:false filter and verify that + // plugin that was deactivated before activating the plugin group is not activated + updatedPlugins, err := inventory.GetPlugins(&PluginInventoryFilter{Name: plugins[0].Name, Target: plugins[0].Target, Version: plugins[0].Version, IncludeHidden: false}) + Expect(err).ToNot(HaveOccurred()) + Expect(len(updatedPlugins)).To(Equal(1)) + Expect(updatedPlugins[0].Name).To(Equal(plugins[0].Name)) + Expect(updatedPlugins[0].Target).To(Equal(plugins[0].Target)) + Expect(updatedPlugins[0].RecommendedVersion).To(Equal(plugins[0].Version)) + Expect(updatedPlugins[0].Hidden).To(BeFalse()) + }) + It("when activating plugin group containing a deactivated plugin without TANZU_CLI_ACTIVATE_PLUGINS_ON_PLUGIN_GROUP_PUBLISH being set, it should NOT activate the deactivated plugin", func() { + pluginGroupUpdated := groupWithHiddenPlugin + pluginGroupUpdated.Hidden = false + err = inventory.UpdatePluginGroupActivationState(&pluginGroupUpdated) + Expect(err).To(BeNil()) + + // Verify the result using GetPluginGroups + groups, err := inventory.GetPluginGroups(PluginGroupFilter{}) + Expect(err).ToNot(HaveOccurred()) + Expect(len(groups)).To(Equal(1)) + pg := groups[0] + + plugins := pg.Versions["v1.0.0"] + Expect(len(plugins)).To(Equal(1)) + Expect(plugins[0].Name).To(Equal(groupWithHiddenPlugin.Versions["v1.0.0"][0].Name)) + Expect(plugins[0].Target).To(Equal(groupWithHiddenPlugin.Versions["v1.0.0"][0].Target)) + Expect(plugins[0].Version).To(Equal(groupWithHiddenPlugin.Versions["v1.0.0"][0].Version)) + Expect(plugins[0].Mandatory).To(Equal(groupWithHiddenPlugin.Versions["v1.0.0"][0].Mandatory)) + + // Try to get the plugin with IncludeHidden:false filter and no plugins should be present + plugins2, err := inventory.GetPlugins(&PluginInventoryFilter{Name: plugins[0].Name, Target: plugins[0].Target, Version: plugins[0].Version, IncludeHidden: false}) + Expect(err).ToNot(HaveOccurred()) + Expect(len(plugins2)).To(Equal(0)) }) }) From 64ee1a99bee67d9e2b1fbce967a5a82edd3615ae Mon Sep 17 00:00:00 2001 From: Anuj Chaudhari Date: Mon, 15 Jul 2024 15:42:32 -0700 Subject: [PATCH 2/2] Address comments --- pkg/plugininventory/sqlite_inventory.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/pkg/plugininventory/sqlite_inventory.go b/pkg/plugininventory/sqlite_inventory.go index 8e9cf4209..128385a08 100644 --- a/pkg/plugininventory/sqlite_inventory.go +++ b/pkg/plugininventory/sqlite_inventory.go @@ -675,7 +675,9 @@ func (b *SQLiteInventory) InsertPluginGroup(pg *PluginGroup, override bool) erro } includeDeactivatedPluginsForTesting, _ := strconv.ParseBool(os.Getenv(constants.ConfigVariableIncludeDeactivatedPluginsForTesting)) + // Only activate plugins if TANZU_CLI_ACTIVATE_PLUGINS_ON_PLUGIN_GROUP_PUBLISH=true and we are PluginGroup is also active (!pg.Hidden) activatePlugins, _ := strconv.ParseBool(os.Getenv(constants.ActivatePluginsOnPluginGroupPublish)) + activatePlugins = activatePlugins && !pg.Hidden // Allow hidden plugins if either of the below configuration is specified allowHiddenPlugins := includeDeactivatedPluginsForTesting || activatePlugins @@ -701,7 +703,7 @@ func (b *SQLiteInventory) InsertPluginGroup(pg *PluginGroup, override bool) erro // environment variable is set to True. // Note: If it is set to false, plugins won't be deactivated if activatePlugins { - err = b.updatePluginActivationState(db, pi.Name, string(pi.Target), pi.Version, true) + err = b.updatePluginVersionActivationState(db, pi.Name, string(pi.Target), pi.Version, true) if err != nil { return errors.Wrap(err, "unable to activate plugin with in plugin group") } @@ -739,7 +741,7 @@ func (b *SQLiteInventory) UpdatePluginActivationState(pluginInventoryEntry *Plug defer db.Close() for version := range pluginInventoryEntry.Artifacts { - err := b.updatePluginActivationState(db, pluginInventoryEntry.Name, string(pluginInventoryEntry.Target), version, !pluginInventoryEntry.Hidden) + err := b.updatePluginVersionActivationState(db, pluginInventoryEntry.Name, string(pluginInventoryEntry.Target), version, !pluginInventoryEntry.Hidden) if err != nil { return err } @@ -747,7 +749,7 @@ func (b *SQLiteInventory) UpdatePluginActivationState(pluginInventoryEntry *Plug return nil } -func (b *SQLiteInventory) updatePluginActivationState(db *sql.DB, name, target, version string, activate bool) error { +func (b *SQLiteInventory) updatePluginVersionActivationState(db *sql.DB, name, target, version string, activate bool) error { result, err := db.Exec("UPDATE PluginBinaries SET hidden = ? WHERE PluginName = ? AND Target = ? AND Version = ? ;", strconv.FormatBool(!activate), name, target, version) if err != nil { return errors.Wrapf(err, "unable to update plugin %v_%v", name, target) @@ -775,9 +777,9 @@ func (b *SQLiteInventory) UpdatePluginGroupActivationState(pg *PluginGroup) erro // environment variable is set to `True` and we are trying to activate the plugin group if activatePlugins && !pg.Hidden { for _, pi := range plugins { - err = b.updatePluginActivationState(db, pi.Name, string(pi.Target), pi.Version, true) + err = b.updatePluginVersionActivationState(db, pi.Name, string(pi.Target), pi.Version, true) if err != nil { - return errors.Wrap(err, "unable to activate plugin with in plugin group") + return errors.Wrap(err, "unable to activate plugin within plugin group") } } }