Refactor ClusterComplexName

This change includes various code cleanups which improve the way that a
developer creates and interacts with ClusterComplexNames.

Change-Id: If3c4326f3ca46db7fd307b50ca260cdb1a82f3f3
This commit is contained in:
Ian Howell 2020-03-25 17:31:15 -05:00
parent cbc1e931ae
commit 567e063589
6 changed files with 129 additions and 137 deletions

View File

@ -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{

View File

@ -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 {

View File

@ -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)
})
}
}

View File

@ -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

View File

@ -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

View File

@ -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_<clusterType>"
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)
}