diff --git a/pkg/api/v1alpha1/cluster_map_types.go b/pkg/api/v1alpha1/cluster_map_types.go index 33b13f717..6b954f0a9 100644 --- a/pkg/api/v1alpha1/cluster_map_types.go +++ b/pkg/api/v1alpha1/cluster_map_types.go @@ -37,6 +37,14 @@ type Cluster struct { DynamicKubeConfig bool `json:"dynamicKubeConf,omitempty"` // KubeconfigContext is the context in kubeconfig, default is equals to clusterMap key KubeconfigContext string `json:"kubeconfigContext,omitempty"` + // ClusterAPIRef references to Cluster API cluster resources + ClusterAPIRef ClusterAPIRef `json:"clusterAPIRef,omitempty"` +} + +// ClusterAPIRef will be used to find cluster object in kubernetes parent cluster +type ClusterAPIRef struct { + Name string + Namespace string } // DefaultClusterMap can be used to safely unmarshal ClusterMap object without nil pointers diff --git a/pkg/api/v1alpha1/zz_generated.deepcopy.go b/pkg/api/v1alpha1/zz_generated.deepcopy.go index 4214e388c..62a48c1d7 100644 --- a/pkg/api/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/api/v1alpha1/zz_generated.deepcopy.go @@ -116,6 +116,7 @@ func (in *Builder) DeepCopy() *Builder { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Cluster) DeepCopyInto(out *Cluster) { *out = *in + out.ClusterAPIRef = in.ClusterAPIRef } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Cluster. @@ -128,6 +129,21 @@ func (in *Cluster) DeepCopy() *Cluster { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterAPIRef) DeepCopyInto(out *ClusterAPIRef) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterAPIRef. +func (in *ClusterAPIRef) DeepCopy() *ClusterAPIRef { + if in == nil { + return nil + } + out := new(ClusterAPIRef) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ClusterMap) DeepCopyInto(out *ClusterMap) { *out = *in diff --git a/pkg/cluster/clustermap/map.go b/pkg/cluster/clustermap/map.go index 3550479b0..f2b135e6c 100644 --- a/pkg/cluster/clustermap/map.go +++ b/pkg/cluster/clustermap/map.go @@ -19,6 +19,9 @@ import ( "opendev.org/airship/airshipctl/pkg/log" ) +// DefaultClusterAPIObjNamespace is a default namespace used for cluster-api cluster object +const DefaultClusterAPIObjNamespace = "default" + // ClusterMap interface that allows to list all clusters, find its parent, namespace, // check if dynamic kubeconfig is enabled. // TODO use typed cluster names @@ -28,6 +31,7 @@ type ClusterMap interface { DynamicKubeConfig(string) bool ClusterNamespace(string) (string, error) ClusterKubeconfigContext(string) (string, error) + ClusterAPIRef(string) (ClusterAPIRef, error) } // clusterMap allows to view clusters and relationship between them @@ -73,6 +77,36 @@ func (cm clusterMap) AllClusters() []string { return clusters } +// ClusterAPIRef helps to find corresponding cluster-api Cluster object in kubernetes cluster +type ClusterAPIRef struct { + Name string + Namespace string +} + +// ClusterAPIRef maps a clusterapi name and namespace for a given cluster +func (cm clusterMap) ClusterAPIRef(clusterName string) (ClusterAPIRef, error) { + clstr, ok := cm.apiMap.Map[clusterName] + if !ok { + return ClusterAPIRef{}, ErrClusterNotInMap{Child: clusterName, Map: cm.apiMap} + } + + name := clstr.ClusterAPIRef.Name + namespace := clstr.ClusterAPIRef.Namespace + + if name == "" { + name = clusterName + } + + if namespace == "" { + namespace = DefaultClusterAPIObjNamespace + } + + return ClusterAPIRef{ + Name: name, + Namespace: namespace, + }, nil +} + // ClusterNamespace a namespace for given cluster // TODO implement how to get namespace for cluster func (cm clusterMap) ClusterNamespace(clusterName string) (string, error) { diff --git a/pkg/cluster/clustermap/map_test.go b/pkg/cluster/clustermap/map_test.go index 955ba6f2a..90b8e6693 100644 --- a/pkg/cluster/clustermap/map_test.go +++ b/pkg/cluster/clustermap/map_test.go @@ -30,6 +30,8 @@ func TestClusterMap(t *testing.T) { workloadCluster := "workload" workloadClusterKubeconfigContext := "different-workload-context" workloadClusterNoParent := "workload without parent" + workloadClusterAPIRefName := "workload-cluster-api" + workloadClusterAPIRefNamespace := "some-namespace" apiMap := &v1alpha1.ClusterMap{ Map: map[string]*v1alpha1.Cluster{ targetCluster: { @@ -41,6 +43,10 @@ func TestClusterMap(t *testing.T) { Parent: targetCluster, DynamicKubeConfig: true, KubeconfigContext: workloadClusterKubeconfigContext, + ClusterAPIRef: v1alpha1.ClusterAPIRef{ + Name: workloadClusterAPIRefName, + Namespace: workloadClusterAPIRefNamespace, + }, }, workloadClusterNoParent: { DynamicKubeConfig: true, @@ -106,4 +112,23 @@ func TestClusterMap(t *testing.T) { _, err := cMap.ClusterKubeconfigContext("does not exist") assert.Error(t, err) }) + + t.Run("ClusterAPI ref name and namespace defaults", func(t *testing.T) { + ref, err := cMap.ClusterAPIRef(workloadClusterNoParent) + assert.NoError(t, err) + assert.Equal(t, clustermap.DefaultClusterAPIObjNamespace, ref.Namespace) + assert.Equal(t, workloadClusterNoParent, ref.Name) + }) + + t.Run("ClusterAPI ref name and namespace", func(t *testing.T) { + ref, err := cMap.ClusterAPIRef(workloadCluster) + assert.NoError(t, err) + assert.Equal(t, workloadClusterAPIRefNamespace, ref.Namespace) + assert.Equal(t, workloadClusterAPIRefName, ref.Name) + }) + + t.Run("ClusterAPI ref error", func(t *testing.T) { + _, err := cMap.ClusterAPIRef("doesn't exist") + assert.Error(t, err) + }) }