diff --git a/cmd/config/set_cluster_test.go b/cmd/config/set_cluster_test.go index f29bb7b07..36f2fa07a 100644 --- a/cmd/config/set_cluster_test.go +++ b/cmd/config/set_cluster_test.go @@ -60,14 +60,13 @@ func TestSetClusterWithCAFile(t *testing.T) { expected.Clusters[tname] = config.NewClusterPurpose() expected.Clusters[tname].ClusterTypes[tctype] = config.NewCluster() - clusterName := config.NewClusterComplexName() - clusterName.WithType(tname, tctype) - expected.Clusters[tname].ClusterTypes[tctype].NameInKubeconf = clusterName.Name() + clusterName := config.NewClusterComplexName(tname, tctype) + expected.Clusters[tname].ClusterTypes[tctype].NameInKubeconf = clusterName.String() expkCluster := kubeconfig.NewCluster() expkCluster.CertificateAuthority = certFile expkCluster.InsecureSkipTLSVerify = false - expected.KubeConfig().Clusters[clusterName.Name()] = expkCluster + expected.KubeConfig().Clusters[clusterName.String()] = expkCluster test := setClusterTest{ description: "Testing 'airshipctl config set-cluster' with a new cluster", @@ -98,9 +97,8 @@ func TestSetClusterWithCAFileData(t *testing.T) { expected.Clusters[tname] = config.NewClusterPurpose() expected.Clusters[tname].ClusterTypes[tctype] = config.NewCluster() - clusterName := config.NewClusterComplexName() - clusterName.WithType(tname, tctype) - expected.Clusters[tname].ClusterTypes[tctype].NameInKubeconf = clusterName.Name() + clusterName := config.NewClusterComplexName(tname, tctype) + expected.Clusters[tname].ClusterTypes[tctype].NameInKubeconf = clusterName.String() expkCluster := kubeconfig.NewCluster() readData, err := ioutil.ReadFile(certFile) @@ -108,7 +106,7 @@ func TestSetClusterWithCAFileData(t *testing.T) { expkCluster.CertificateAuthorityData = readData expkCluster.InsecureSkipTLSVerify = false - expected.KubeConfig().Clusters[clusterName.Name()] = expkCluster + expected.KubeConfig().Clusters[clusterName.String()] = expkCluster test := setClusterTest{ description: "Testing 'airshipctl config set-cluster' with a new cluster", @@ -138,14 +136,13 @@ func TestSetCluster(t *testing.T) { expected.Clusters[tname] = config.NewClusterPurpose() expected.Clusters[tname].ClusterTypes[tctype] = config.NewCluster() - clusterName := config.NewClusterComplexName() - clusterName.WithType(tname, tctype) - expected.Clusters[tname].ClusterTypes[tctype].NameInKubeconf = clusterName.Name() + clusterName := config.NewClusterComplexName(tname, tctype) + expected.Clusters[tname].ClusterTypes[tctype].NameInKubeconf = clusterName.String() expkCluster := kubeconfig.NewCluster() expkCluster.Server = "https://192.168.0.11" expkCluster.InsecureSkipTLSVerify = false - expected.KubeConfig().Clusters[clusterName.Name()] = expkCluster + expected.KubeConfig().Clusters[clusterName.String()] = expkCluster test := setClusterTest{ description: "Testing 'airshipctl config set-cluster' with a new cluster", @@ -170,13 +167,12 @@ func TestModifyCluster(t *testing.T) { defer cleanupGiven(t) given.Clusters[tname] = config.NewClusterPurpose() - clusterName := config.NewClusterComplexName() - clusterName.WithType(tname, tctype) + clusterName := config.NewClusterComplexName(tname, tctype) given.Clusters[tname].ClusterTypes[tctype] = config.NewCluster() - given.Clusters[tname].ClusterTypes[tctype].NameInKubeconf = clusterName.Name() + given.Clusters[tname].ClusterTypes[tctype].NameInKubeconf = clusterName.String() cluster := kubeconfig.NewCluster() cluster.Server = "https://192.168.0.10" - given.KubeConfig().Clusters[clusterName.Name()] = cluster + given.KubeConfig().Clusters[clusterName.String()] = cluster given.Clusters[tname].ClusterTypes[tctype].SetKubeCluster(cluster) expected, cleanupExpected := testutil.InitConfig(t) @@ -184,10 +180,10 @@ func TestModifyCluster(t *testing.T) { expected.Clusters[tname] = config.NewClusterPurpose() expected.Clusters[tname].ClusterTypes[tctype] = config.NewCluster() - expected.Clusters[tname].ClusterTypes[tctype].NameInKubeconf = clusterName.Name() + expected.Clusters[tname].ClusterTypes[tctype].NameInKubeconf = clusterName.String() expkCluster := kubeconfig.NewCluster() expkCluster.Server = "https://192.168.0.10" - expected.KubeConfig().Clusters[clusterName.Name()] = expkCluster + expected.KubeConfig().Clusters[clusterName.String()] = expkCluster expected.Clusters[tname].ClusterTypes[tctype].SetKubeCluster(expkCluster) test := setClusterTest{ diff --git a/pkg/config/config.go b/pkg/config/config.go index 79ba99f74..c22ae80b0 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -153,19 +153,17 @@ func (c *Config) reconcileClusters() (map[string]string, bool) { persistIt := false for clusterName, cluster := range c.kubeConfig.Clusters { - clusterComplexName := NewClusterComplexName() - clusterComplexName.FromName(clusterName) + clusterComplexName := NewClusterComplexNameFromKubeClusterName(clusterName) // Check if the cluster from the kubeconfig file complies with // the airship naming convention - if !clusterComplexName.validName() { - clusterComplexName.SetDefaultType() + if clusterName != clusterComplexName.String() { // Update the kubeconfig with proper airship name - c.kubeConfig.Clusters[clusterComplexName.Name()] = cluster + c.kubeConfig.Clusters[clusterComplexName.String()] = cluster delete(c.kubeConfig.Clusters, clusterName) // We also need to save the mapping from the old name // so we can update the context in the kubeconfig later - updatedClusterNames[clusterName] = clusterComplexName.Name() + updatedClusterNames[clusterName] = clusterComplexName.String() // Since we've modified the kubeconfig object, we'll // need to let the caller know that the kubeconfig file @@ -179,17 +177,16 @@ func (c *Config) reconcileClusters() (map[string]string, bool) { } // Update the airship config file - if c.Clusters[clusterComplexName.ClusterName()] == nil { - c.Clusters[clusterComplexName.ClusterName()] = NewClusterPurpose() + if c.Clusters[clusterComplexName.Name] == nil { + c.Clusters[clusterComplexName.Name] = NewClusterPurpose() } - if c.Clusters[clusterComplexName.ClusterName()].ClusterTypes[clusterComplexName.ClusterType()] == nil { - c.Clusters[clusterComplexName.ClusterName()].ClusterTypes[clusterComplexName.ClusterType()] = NewCluster() - } - configCluster := c.Clusters[clusterComplexName.ClusterName()].ClusterTypes[clusterComplexName.ClusterType()] - if configCluster.NameInKubeconf != clusterComplexName.Name() { - configCluster.NameInKubeconf = clusterComplexName.Name() - // TODO What do we do with the BOOTSTRAP CONFIG + if c.Clusters[clusterComplexName.Name].ClusterTypes[clusterComplexName.Type] == nil { + c.Clusters[clusterComplexName.Name].ClusterTypes[clusterComplexName.Type] = NewCluster() } + configCluster := c.Clusters[clusterComplexName.Name].ClusterTypes[clusterComplexName.Type] + configCluster.NameInKubeconf = clusterComplexName.String() + // TODO What do we do with the BOOTSTRAP CONFIG + // Store the reference to the KubeConfig Cluster in the Airship Config configCluster.SetKubeCluster(cluster) } @@ -239,11 +236,10 @@ func (c *Config) reconcileContexts(updatedClusterNames map[string]string) { c.Contexts[key].NameInKubeconf = context.Cluster c.Contexts[key].SetKubeContext(context) - // What about if a Context refers to a properly named cluster - // that does not exist in airship config - clusterName := NewClusterComplexName() - clusterName.FromName(context.Cluster) - if clusterName.validName() && c.Clusters[clusterName.ClusterName()] == nil { + // What about if a Context refers to a cluster that does not + // exist in airship config + clusterName := NewClusterComplexNameFromKubeClusterName(context.Cluster) + if c.Clusters[clusterName.Name] == nil { // I cannot create this cluster, it will have empty information // Best course of action is to delete it I think delete(c.kubeConfig.Contexts, key) @@ -446,12 +442,11 @@ func (c *Config) AddCluster(theCluster *ClusterOptions) (*Cluster, error) { c.Clusters[theCluster.Name].ClusterTypes[theCluster.ClusterType] = nCluster // Create a new KubeConfig Cluster object as well kcluster := clientcmdapi.NewCluster() - clusterName := NewClusterComplexName() - clusterName.WithType(theCluster.Name, theCluster.ClusterType) - nCluster.NameInKubeconf = clusterName.Name() + clusterName := NewClusterComplexName(theCluster.Name, theCluster.ClusterType) + nCluster.NameInKubeconf = clusterName.String() nCluster.SetKubeCluster(kcluster) - c.KubeConfig().Clusters[clusterName.Name()] = kcluster + c.KubeConfig().Clusters[clusterName.String()] = kcluster // Ok , I have initialized structs for the Cluster information // We can use Modify to populate the correct information @@ -556,8 +551,6 @@ func (c *Config) AddContext(theContext *ContextOptions) *Context { // Create a new KubeConfig Context object as well context := clientcmdapi.NewContext() nContext.NameInKubeconf = theContext.Name - contextName := NewClusterComplexName() - contextName.WithType(theContext.Name, theContext.ClusterType) nContext.SetKubeContext(context) c.KubeConfig().Contexts[theContext.Name] = context @@ -610,10 +603,9 @@ func (c *Config) CurrentContextCluster() (*Cluster, error) { if err != nil { return nil, err } - clusterName := NewClusterComplexName() - clusterName.FromName(currentContext.KubeContext().Cluster) + clusterName := NewClusterComplexNameFromKubeClusterName(currentContext.KubeContext().Cluster) - return c.Clusters[clusterName.ClusterName()].ClusterTypes[currentContext.ClusterType()], nil + return c.Clusters[clusterName.Name].ClusterTypes[currentContext.ClusterType()], nil } func (c *Config) CurrentContextAuthInfo() (*AuthInfo, error) { @@ -755,11 +747,8 @@ func (c *Cluster) String() string { } func (c *Cluster) PrettyString() string { - clusterName := NewClusterComplexName() - clusterName.FromName(c.NameInKubeconf) - - return fmt.Sprintf("Cluster: %s\n%s:\n%s", - clusterName.ClusterName(), clusterName.ClusterType(), c) + clusterName := NewClusterComplexNameFromKubeClusterName(c.NameInKubeconf) + return fmt.Sprintf("Cluster: %s\n%s:\n%s", clusterName.Name, clusterName.Type, c) } func (c *Cluster) KubeCluster() *clientcmdapi.Cluster { @@ -784,11 +773,8 @@ func (c *Context) String() string { } func (c *Context) PrettyString() string { - clusterName := NewClusterComplexName() - clusterName.FromName(c.NameInKubeconf) - - return fmt.Sprintf("Context: %s\n%s\n", - clusterName.ClusterName(), c.String()) + clusterName := NewClusterComplexNameFromKubeClusterName(c.NameInKubeconf) + return fmt.Sprintf("Context: %s\n%s\n", clusterName.Name, c) } func (c *Context) KubeContext() *clientcmdapi.Context { @@ -800,9 +786,7 @@ func (c *Context) SetKubeContext(kc *clientcmdapi.Context) { } func (c *Context) ClusterType() string { - clusterName := NewClusterComplexName() - clusterName.FromName(c.NameInKubeconf) - return clusterName.ClusterType() + return NewClusterComplexNameFromKubeClusterName(c.NameInKubeconf).Type } // AuthInfo functions @@ -867,60 +851,10 @@ func (b *Builder) String() string { return string(yamlData) } -// ClusterComplexName functions -func (c *ClusterComplexName) validName() bool { - err := ValidClusterType(c.clusterType) - return c.clusterName != "" && err == nil -} - -func (c *ClusterComplexName) FromName(clusterName string) { - if clusterName == "" { - return - } - - userNameSplit := strings.Split(clusterName, AirshipClusterNameSep) - if len(userNameSplit) == 1 { - c.clusterName = clusterName - return - } - - for _, cType := range AllClusterTypes { - if userNameSplit[len(userNameSplit)-1] == cType { - c.clusterType = userNameSplit[len(userNameSplit)-1] - c.clusterName = strings.Join(userNameSplit[:len(userNameSplit)-1], AirshipClusterNameSep) - return - } - } -} - -func (c *ClusterComplexName) WithType(clusterName string, clusterType string) { - c.FromName(clusterName) - c.SetClusterType(clusterType) -} -func (c *ClusterComplexName) Name() string { - s := []string{c.clusterName, c.clusterType} - return strings.Join(s, AirshipClusterNameSep) -} -func (c *ClusterComplexName) ClusterName() string { - return c.clusterName -} - -func (c *ClusterComplexName) ClusterType() string { - return c.clusterType -} -func (c *ClusterComplexName) SetClusterName(cn string) { - c.clusterName = cn -} - -func (c *ClusterComplexName) SetClusterType(ct string) { - c.clusterType = ct -} -func (c *ClusterComplexName) SetDefaultType() { - c.SetClusterType(AirshipClusterDefaultType) -} func (c *ClusterComplexName) String() string { - return fmt.Sprintf("clusterName:%s, clusterType:%s", c.clusterName, c.clusterType) + return strings.Join([]string{c.Name, c.Type}, AirshipClusterNameSeparator) } + func ValidClusterType(clusterType string) error { for _, validType := range AllClusterTypes { if clusterType == validType { diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index 8e657f309..8acb9e678 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -307,23 +307,6 @@ func TestPurge(t *testing.T) { assert.Falsef(t, os.IsExist(err), "Purge failed to remove file at %v", conf.LoadedConfigPath()) } -func TestComplexName(t *testing.T) { - cName := "aCluster" - ctName := config.Ephemeral - clusterName := config.NewClusterComplexName() - clusterName.WithType(cName, ctName) - assert.EqualValues(t, cName+"_"+ctName, clusterName.Name()) - assert.EqualValues(t, cName, clusterName.ClusterName()) - assert.EqualValues(t, ctName, clusterName.ClusterType()) - - cName = "bCluster" - clusterName.SetClusterName(cName) - clusterName.SetDefaultType() - ctName = clusterName.ClusterType() - assert.EqualValues(t, cName+"_"+ctName, clusterName.Name()) - assert.EqualValues(t, "clusterName:"+cName+", clusterType:"+ctName, clusterName.String()) -} - func TestValidClusterTypeFail(t *testing.T) { err := config.ValidClusterType("Fake") assert.Error(t, err) @@ -626,3 +609,46 @@ func TestModifyAuthInfo(t *testing.T) { assert.EqualValues(t, conf.AuthInfos[co.Name].KubeAuthInfo().Token, co.Token) assert.EqualValues(t, conf.AuthInfos[co.Name], authinfo) } + +func TestNewClusterComplexNameFromKubeClusterName(t *testing.T) { + tests := []struct { + name string + inputName string + expectedName string + expectedType string + }{ + { + name: "single-word", + inputName: "myCluster", + expectedName: "myCluster", + expectedType: config.AirshipDefaultClusterType, + }, + { + name: "multi-word", + inputName: "myCluster_two", + expectedName: "myCluster_two", + expectedType: config.AirshipDefaultClusterType, + }, + { + name: "cluster-appended", + inputName: "myCluster_ephemeral", + expectedName: "myCluster", + expectedType: config.Ephemeral, + }, + { + name: "multi-word-cluster-appended", + inputName: "myCluster_two_ephemeral", + expectedName: "myCluster_two", + expectedType: config.Ephemeral, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + complexName := config.NewClusterComplexNameFromKubeClusterName(tt.inputName) + assert.Equal(t, tt.expectedName, complexName.Name) + assert.Equal(t, tt.expectedType, complexName.Type) + }) + } +} diff --git a/pkg/config/constants.go b/pkg/config/constants.go index f47c10c5f..6360dbad1 100644 --- a/pkg/config/constants.go +++ b/pkg/config/constants.go @@ -2,10 +2,10 @@ package config // Constants related to the ClusterType type const ( - Ephemeral = "ephemeral" - Target = "target" - AirshipClusterNameSep = "_" - AirshipClusterDefaultType = Target + Ephemeral = "ephemeral" + Target = "target" + AirshipClusterNameSeparator = "_" + AirshipDefaultClusterType = Target ) // Constants related to Phases diff --git a/pkg/config/types.go b/pkg/config/types.go index 64e255a12..d61e9fcc3 100644 --- a/pkg/config/types.go +++ b/pkg/config/types.go @@ -182,8 +182,8 @@ type RepoCheckout struct { // Holds the complex cluster name information // Encapsulates the different operations around using it. type ClusterComplexName struct { - clusterName string - clusterType string + Name string + Type string } // Bootstrap holds configurations for bootstrap steps diff --git a/pkg/config/utils.go b/pkg/config/utils.go index bdf6ffd3f..a57720a67 100644 --- a/pkg/config/utils.go +++ b/pkg/config/utils.go @@ -16,6 +16,8 @@ limitations under the License. package config +import "strings" + const ( DefaultTestPrimaryRepo = "primary" ) @@ -112,6 +114,40 @@ func NewClusterPurpose() *ClusterPurpose { } } -func NewClusterComplexName() *ClusterComplexName { - return &ClusterComplexName{} +// NewClusterComplexName returns a ClusterComplexName with the given name and type. +func NewClusterComplexName(clusterName, clusterType string) ClusterComplexName { + return ClusterComplexName{ + Name: clusterName, + Type: clusterType, + } +} + +// NewClusterComplexNameFromKubeClusterName takes the name of a cluster in a +// format which might be found in a kubeconfig file. This may be a simple +// string (e.g. myCluster), or it may be prepended with the type of the cluster +// (e.g. myCluster_target) +// +// If a valid cluster type was appended, the returned ClusterComplexName will +// have that type. If no cluster type is provided, the +// AirshipDefaultClusterType will be used. +func NewClusterComplexNameFromKubeClusterName(kubeClusterName string) ClusterComplexName { + parts := strings.Split(kubeClusterName, AirshipClusterNameSeparator) + + if len(parts) == 1 { + return NewClusterComplexName(kubeClusterName, AirshipDefaultClusterType) + } + + // kubeClusterName matches the format myCluster_something. + // Let's check if "something" is a clusterType. + potentialType := parts[len(parts)-1] + for _, ct := range AllClusterTypes { + if potentialType == ct { + // Rejoin the parts in the case of "my_cluster_etc_etc_" + name := strings.Join(parts[:len(parts)-1], AirshipClusterNameSeparator) + return NewClusterComplexName(name, potentialType) + } + } + + // "something" is not a valid clusterType, so just use the default + return NewClusterComplexName(kubeClusterName, AirshipDefaultClusterType) }