Skip to content

Commit

Permalink
Implement clusterctl move support for cross-ns CC
Browse files Browse the repository at this point in the history
Signed-off-by: Danil-Grigorev <danil.grigorev@suse.com>
  • Loading branch information
Danil-Grigorev committed Jan 9, 2025
1 parent 03780fe commit bc1b8fc
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 11 deletions.
12 changes: 12 additions & 0 deletions cmd/clusterctl/client/cluster/mover_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1846,6 +1846,8 @@ func Test_objectMoverService_ensureNamespaces(t *testing.T) {

cluster1 := test.NewFakeCluster("namespace-1", "cluster-1")
cluster2 := test.NewFakeCluster("namespace-2", "cluster-2")
cluster3 := test.NewFakeCluster("namespace-1", "cluster-3").WithTopologyClass("cluster-class-1").WithTopologyClassWithin("namespace-2")
clusterClass1 := test.NewFakeClusterClass("namespace-2", "cluster-class-1")
globalObj := test.NewFakeClusterExternalObject("eo-1")

clustersObjs := append(cluster1.Objs(), cluster2.Objs()...)
Expand Down Expand Up @@ -1876,6 +1878,16 @@ func Test_objectMoverService_ensureNamespaces(t *testing.T) {
},
expectedNamespaces: []string{"namespace-1", "namespace-2"},
},
{
name: "ensureNamespaces moves namespace-1 and namespace-2 from cross-namespace CC reference",
fields: fields{
objs: append(cluster3.Objs(), clusterClass1.Objs()...),
},
args: args{
toProxy: test.NewFakeProxy(),
},
expectedNamespaces: []string{"namespace-1", "namespace-2"},
},
{
name: "ensureNamespaces moves namespace-2 to target which already has namespace-1",
fields: fields{
Expand Down
10 changes: 9 additions & 1 deletion cmd/clusterctl/client/cluster/objectgraph.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import (
)

const clusterTopologyNameKey = "cluster.spec.topology.class"
const clusterTopologyNamespaceKey = "cluster.spec.topology.classNamespace"
const clusterResourceSetBindingClusterNameKey = "clusterresourcesetbinding.spec.clustername"

type empty struct{}
Expand Down Expand Up @@ -149,6 +150,7 @@ func (n *node) captureAdditionalInformation(obj *unstructured.Unstructured) erro
n.additionalInfo = map[string]interface{}{}
}
n.additionalInfo[clusterTopologyNameKey] = cluster.GetClassKey().Name
n.additionalInfo[clusterTopologyNamespaceKey] = cluster.GetClassKey().Namespace
}
}

Expand Down Expand Up @@ -620,7 +622,13 @@ func (o *objectGraph) setSoftOwnership() {
for _, cluster := range clusters {
// if the cluster uses a managed topology and uses the clusterclass
// set the clusterclass as a soft owner of the cluster.
if className, ok := cluster.additionalInfo[clusterTopologyNameKey]; ok {
className, hasName := cluster.additionalInfo[clusterTopologyNameKey]
classNamespace, hasNamespace := cluster.additionalInfo[clusterTopologyNamespaceKey]
if hasNamespace && hasName {
if className == clusterClass.identity.Name && clusterClass.identity.Namespace == classNamespace {
cluster.addSoftOwner(clusterClass)
}
} else if hasName {
if className == clusterClass.identity.Name && clusterClass.identity.Namespace == cluster.identity.Namespace {
cluster.addSoftOwner(clusterClass)
}
Expand Down
51 changes: 51 additions & 0 deletions cmd/clusterctl/client/cluster/objectgraph_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2047,6 +2047,57 @@ func Test_objectGraph_setSoftOwnership(t *testing.T) {
},
},
},
{
name: "A different namespaced ClusterClass with a soft owned Cluster",
fields: fields{
objs: func() []client.Object {
objs := test.NewFakeClusterClass("ns1", "class1").Objs()
objs = append(objs, test.NewFakeCluster("ns2", "cluster1").WithTopologyClass("class1").WithTopologyClassWithin("ns1").Objs()...)

return objs
}(),
},
want: wantGraph{
nodes: map[string]wantGraphItem{
"cluster.x-k8s.io/v1beta1, Kind=ClusterClass, ns1/class1": {
forceMove: true,
forceMoveHierarchy: true,
},
"infrastructure.cluster.x-k8s.io/v1beta1, Kind=GenericInfrastructureClusterTemplate, ns1/class1": {
owners: []string{
"cluster.x-k8s.io/v1beta1, Kind=ClusterClass, ns1/class1",
},
},
"controlplane.cluster.x-k8s.io/v1beta1, Kind=GenericControlPlaneTemplate, ns1/class1": {
owners: []string{
"cluster.x-k8s.io/v1beta1, Kind=ClusterClass, ns1/class1",
},
},
"cluster.x-k8s.io/v1beta1, Kind=Cluster, ns2/cluster1": {
forceMove: true,
forceMoveHierarchy: true,
softOwners: []string{
"cluster.x-k8s.io/v1beta1, Kind=ClusterClass, ns1/class1", // NB. this cluster is not linked to the clusterclass through owner ref, but it is detected as soft ownership
},
},
"infrastructure.cluster.x-k8s.io/v1beta1, Kind=GenericInfrastructureCluster, ns2/cluster1": {
owners: []string{
"cluster.x-k8s.io/v1beta1, Kind=Cluster, ns2/cluster1",
},
},
"/v1, Kind=Secret, ns2/cluster1-ca": {
softOwners: []string{
"cluster.x-k8s.io/v1beta1, Kind=Cluster, ns2/cluster1", // NB. this secret is not linked to the cluster through owner ref, but it is detected as soft ownership
},
},
"/v1, Kind=Secret, ns2/cluster1-kubeconfig": {
owners: []string{
"cluster.x-k8s.io/v1beta1, Kind=Cluster, ns2/cluster1",
},
},
},
},
},
{
name: "A Cluster with a soft owned ClusterResourceSetBinding",
fields: fields{
Expand Down
29 changes: 19 additions & 10 deletions cmd/clusterctl/internal/test/fake_objects.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,17 @@ import (
)

type FakeCluster struct {
namespace string
name string
controlPlane *FakeControlPlane
machinePools []*FakeMachinePool
machineDeployments []*FakeMachineDeployment
machineSets []*FakeMachineSet
machines []*FakeMachine
withCloudConfigSecret bool
withCredentialSecret bool
topologyClass *string
namespace string
name string
controlPlane *FakeControlPlane
machinePools []*FakeMachinePool
machineDeployments []*FakeMachineDeployment
machineSets []*FakeMachineSet
machines []*FakeMachine
withCloudConfigSecret bool
withCredentialSecret bool
topologyClass *string
topologyClassNamespace *string
}

// NewFakeCluster return a FakeCluster that can generate a cluster object, all its own ancillary objects:
Expand Down Expand Up @@ -109,6 +110,11 @@ func (f *FakeCluster) WithTopologyClass(class string) *FakeCluster {
return f
}

func (f *FakeCluster) WithTopologyClassWithin(namespace string) *FakeCluster {
f.topologyClassNamespace = &namespace
return f
}

func (f *FakeCluster) Objs() []client.Object {
clusterInfrastructure := &fakeinfrastructure.GenericInfrastructureCluster{
TypeMeta: metav1.TypeMeta{
Expand Down Expand Up @@ -145,6 +151,9 @@ func (f *FakeCluster) Objs() []client.Object {

if f.topologyClass != nil {
cluster.Spec.Topology = &clusterv1.Topology{Class: *f.topologyClass}
if f.topologyClassNamespace != nil {
cluster.Spec.Topology.ClassNamespace = *f.topologyClassNamespace
}
}

// Ensure the cluster gets a UID to be used by dependant objects for creating OwnerReferences.
Expand Down

0 comments on commit bc1b8fc

Please sign in to comment.