From 122d2b2e89bceb36760e68d001090f55bdac9e8b Mon Sep 17 00:00:00 2001 From: Prem Kumar Kalle Date: Wed, 4 Oct 2023 17:11:27 -0700 Subject: [PATCH] Ensure the k8s and application-engine current contexts are mutual exclusive Signed-off-by: Prem Kumar Kalle --- go.mod | 2 + go.sum | 2 - pkg/command/root.go | 9 +++ pkg/fakes/config/tanzu_config_ng_2.yaml | 55 +++++++++++++++ pkg/pluginmanager/manager.go | 7 ++ pkg/utils/common.go | 18 +++++ pkg/utils/common_test.go | 90 +++++++++++++++++++++++++ 7 files changed, 181 insertions(+), 2 deletions(-) create mode 100644 pkg/fakes/config/tanzu_config_ng_2.yaml diff --git a/go.mod b/go.mod index 1aa7bcdad..f2473e93c 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,8 @@ replace cloud.google.com/go => cloud.google.com/go v0.102.1 replace github.com/vmware-tanzu/tanzu-cli/test/e2e/framework => ./test/e2e/framework +replace github.com/vmware-tanzu/tanzu-plugin-runtime => ../tanzu-plugin-runtime + require ( github.com/AlecAivazis/survey/v2 v2.3.6 github.com/Masterminds/semver v1.5.0 diff --git a/go.sum b/go.sum index 89a5ef5dc..8240b76af 100644 --- a/go.sum +++ b/go.sum @@ -735,8 +735,6 @@ github.com/vmware-tanzu/tanzu-framework/apis/run v0.0.0-20230419030809-7081502eb github.com/vmware-tanzu/tanzu-framework/apis/run v0.0.0-20230419030809-7081502ebf68/go.mod h1:e1Uef+Ux5BIHpYwqbeP2ZZmOzehBcez2vUEWXHe+xHE= github.com/vmware-tanzu/tanzu-framework/capabilities/client v0.0.0-20230523145612-1c6fbba34686 h1:VcuXqUXFxm5WDqWkzAlU/6cJXua0ozELnqD59fy7J6E= github.com/vmware-tanzu/tanzu-framework/capabilities/client v0.0.0-20230523145612-1c6fbba34686/go.mod h1:AFGOXZD4tH+KhpmtV0VjWjllXhr8y57MvOsIxTtywc4= -github.com/vmware-tanzu/tanzu-plugin-runtime v1.1.0-dev.0.20231002160823-1da8552a1589 h1:D6B0U5whz3LZvMokKpxYBBHNzkdbhPQOpNKBuJ/B+ho= -github.com/vmware-tanzu/tanzu-plugin-runtime v1.1.0-dev.0.20231002160823-1da8552a1589/go.mod h1:wMK/qpJjU7hytDAGt3FX5/iGdlUK8TsJLu36pCr+Zvk= github.com/xanzy/go-gitlab v0.83.0 h1:37p0MpTPNbsTMKX/JnmJtY8Ch1sFiJzVF342+RvZEGw= github.com/xanzy/go-gitlab v0.83.0/go.mod h1:5ryv+MnpZStBH8I/77HuQBsMbBGANtVpLWC15qOjWAw= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= diff --git a/pkg/command/root.go b/pkg/command/root.go index 88cc71ddc..1479cb23d 100644 --- a/pkg/command/root.go +++ b/pkg/command/root.go @@ -22,6 +22,7 @@ import ( "github.com/vmware-tanzu/tanzu-cli/pkg/pluginmanager" "github.com/vmware-tanzu/tanzu-cli/pkg/pluginsupplier" "github.com/vmware-tanzu/tanzu-cli/pkg/telemetry" + "github.com/vmware-tanzu/tanzu-cli/pkg/utils" "github.com/vmware-tanzu/tanzu-plugin-runtime/config" configtypes "github.com/vmware-tanzu/tanzu-plugin-runtime/config/types" @@ -163,6 +164,14 @@ func newRootCmd() *cobra.Command { } return nil }, + PersistentPostRunE: func(cmd *cobra.Command, args []string) error { + // Ensure mutual exclusion in current contexts just in case if any plugins with old + // plugin-runtime sets k8s context as current when tae context is already set as current + if err := utils.EnsureMutualExclusiveCurrentContexts(); err != nil { + return err + } + return nil + }, } return rootCmd } diff --git a/pkg/fakes/config/tanzu_config_ng_2.yaml b/pkg/fakes/config/tanzu_config_ng_2.yaml new file mode 100644 index 000000000..5e1f43556 --- /dev/null +++ b/pkg/fakes/config/tanzu_config_ng_2.yaml @@ -0,0 +1,55 @@ +contexts: + - name: test-mc-context + target: kubernetes + clusterOpts: + isManagementCluster: true + endpoint: test-endpoint + path: test-path + context: test-mc-context + discoverySources: + - gcp: + name: test + bucket: test-bucket + manifestPath: test-manifest-path + - name: test-use-context + target: mission-control + globalOpts: + endpoint: test-endpoint2 + auth: + IDToken: test-id-token + accessToken: test-access-token + type: api-token + userName: test-user-name + refresh_token: test-refresh-token + - name: test-tmc-context + target: mission-control + globalOpts: + endpoint: test-endpoint3 + auth: + IDToken: test-id-token2 + accessToken: test-access-token2 + type: api-token2 + userName: test-user-name2 + refresh_token: test-refresh-token2 + - name: test-tae-context + target: application-engine + globalOpts: + endpoint: tae-endpoint + auth: + IDToken: test-id-token + accessToken: test-access-token + type: api-token + userName: test-user-name + refresh_token: test-refresh-token + clusterOpts: + isManagementCluster: false + endpoint: kube-endpoint + path: dummy/path + context: dummy-context + additionalMetadata: + taeProjectName: dummyP + taeOrgID: dummyO +currentContext: + kubernetes: test-mc-context + mission-control: test-tmc-context + application-engine: test-tae-context diff --git a/pkg/pluginmanager/manager.go b/pkg/pluginmanager/manager.go index 9256ceb38..077255b63 100644 --- a/pkg/pluginmanager/manager.go +++ b/pkg/pluginmanager/manager.go @@ -975,6 +975,13 @@ 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...") + // ensure the k8s and tae current contexts are mutually exclusive. + // This is required as plugins could call syncPlugins through plugin-runtime + err := utils.EnsureMutualExclusiveCurrentContexts() + if err != nil { + return err + } + errList := make([]error, 0) // We no longer sync standalone plugins. // With a centralized approach to discovering plugins, synchronizing diff --git a/pkg/utils/common.go b/pkg/utils/common.go index dbeb8f11f..bace47b03 100644 --- a/pkg/utils/common.go +++ b/pkg/utils/common.go @@ -6,6 +6,9 @@ package utils import ( "strings" + + "github.com/vmware-tanzu/tanzu-plugin-runtime/config" + configtypes "github.com/vmware-tanzu/tanzu-plugin-runtime/config/types" ) // ContainsString checks the string contains in string array @@ -30,3 +33,18 @@ func ContainsString(arr []string, str string) bool { func GenerateKey(parts ...string) string { return strings.Join(parts, ":") } + +// EnsureMutualExclusiveCurrentContexts ensures mutual exclusive behavior among k8s and tae current contexts, +// i.e, if both k8s and tae current contexts types are set (a case where plugin using old plugin-runtime API +// can set k8s current context though tae current context is set by CLI or plugin with latest plugin-runtime +// in config file) it would remove the tae current context to maintain backward compatibility +func EnsureMutualExclusiveCurrentContexts() error { + ccmap, err := config.GetAllCurrentContextsMap() + if err != nil { + return err + } + if ccmap[configtypes.TargetK8s] != nil && ccmap[configtypes.TargetTAE] != nil { + return config.RemoveCurrentContext(configtypes.TargetTAE) + } + return nil +} diff --git a/pkg/utils/common_test.go b/pkg/utils/common_test.go index 935b5d8ab..1858d68b8 100644 --- a/pkg/utils/common_test.go +++ b/pkg/utils/common_test.go @@ -4,7 +4,15 @@ package utils import ( + "os" + "path/filepath" "testing" + + "github.com/otiai10/copy" + "github.com/stretchr/testify/assert" + + "github.com/vmware-tanzu/tanzu-plugin-runtime/config" + configtypes "github.com/vmware-tanzu/tanzu-plugin-runtime/config/types" ) // TestContainsString tests the ContainsString function. @@ -87,3 +95,85 @@ func TestGenerateKey(t *testing.T) { }) } } + +func setupMultiConcurrentContexts(t *testing.T) func() { + tkgConfigFile, err := os.CreateTemp("", "config") + assert.NoError(t, err) + err = copy.Copy(filepath.Join("..", "fakes", "config", "tanzu_config.yaml"), tkgConfigFile.Name()) + assert.NoError(t, err, "Error while copying tanzu config file for testing") + os.Setenv("TANZU_CONFIG", tkgConfigFile.Name()) + + tkgConfigFileNG, err := os.CreateTemp("", "config_ng") + assert.NoError(t, err) + os.Setenv("TANZU_CONFIG_NEXT_GEN", tkgConfigFileNG.Name()) + err = copy.Copy(filepath.Join("..", "fakes", "config", "tanzu_config_ng_2.yaml"), tkgConfigFileNG.Name()) + assert.NoError(t, err, "Error while copying tanzu-ng config file for testing") + + cleanup := func() { + err = os.Remove(tkgConfigFile.Name()) + assert.NoError(t, err) + err = os.Unsetenv("TANZU_CONFIG") + assert.NoError(t, err) + + err = os.Remove(tkgConfigFileNG.Name()) + assert.NoError(t, err) + err = os.Unsetenv("TANZU_CONFIG_NEXT_GEN") + assert.NoError(t, err) + } + return cleanup +} + +// TestGenerateKey tests the GenerateKey function. +func TestEnsureMutualExclusiveCurrentContexts(t *testing.T) { + cleanup := setupMultiConcurrentContexts(t) + + defer func() { + cleanup() + }() + + // it should remove the tae current context and keep k8s and tmc current context + err := EnsureMutualExclusiveCurrentContexts() + assert.NoError(t, err) + + ccmap, err := config.GetAllCurrentContextsMap() + assert.NoError(t, err) + assert.Equal(t, ccmap[configtypes.TargetK8s].Name, "test-mc-context") + assert.Equal(t, ccmap[configtypes.TargetTMC].Name, "test-tmc-context") + assert.Nil(t, ccmap[configtypes.TargetTAE]) + + // if there is only k8s current context, calling again should not affect the current contexts + err = EnsureMutualExclusiveCurrentContexts() + assert.NoError(t, err) + + ccmap, err = config.GetAllCurrentContextsMap() + assert.NoError(t, err) + assert.Equal(t, ccmap[configtypes.TargetK8s].Name, "test-mc-context") + assert.Equal(t, ccmap[configtypes.TargetTMC].Name, "test-tmc-context") + assert.Nil(t, ccmap[configtypes.TargetTAE]) + + // if there is only tae current context, calling again should not affect the current contexts + err = config.SetCurrentContext("test-tae-context") + assert.NoError(t, err) + + err = EnsureMutualExclusiveCurrentContexts() + assert.NoError(t, err) + + ccmap, err = config.GetAllCurrentContextsMap() + assert.NoError(t, err) + assert.Nil(t, ccmap[configtypes.TargetK8s]) + assert.Equal(t, ccmap[configtypes.TargetTMC].Name, "test-tmc-context") + assert.Equal(t, ccmap[configtypes.TargetTAE].Name, "test-tae-context") + + // if there are no current context, calling again should not affect the current contexts + err = config.RemoveCurrentContext(configtypes.TargetTAE) + assert.NoError(t, err) + err = config.RemoveCurrentContext(configtypes.TargetTMC) + assert.NoError(t, err) + + err = EnsureMutualExclusiveCurrentContexts() + assert.NoError(t, err) + + ccmap, err = config.GetAllCurrentContextsMap() + assert.NoError(t, err) + assert.Equal(t, len(ccmap), 0) +}