Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🌱 clusterctl move ClusterResourceSets #3243

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions cmd/clusterctl/client/cluster/mover.go
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ func getMoveSequence(graph *objectGraph) *moveSequence {
// NB. it is necessary to filter out nodes not belonging to a cluster because e.g. discovery reads all the secrets,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In L120, do we need to check control plane ready condition instead of clusterObj.Status.ControlPlaneReady ?
In my setup I don't see Status.controlPlaneReady anymore.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is required to install the CNI in order to get Status.controlPlaneReady

// but only few of them are related to Clusters/Machines etc.
moveGroup := moveGroup{}
for _, n := range graph.getNodesWithClusterTenants() {
for _, n := range graph.getNodesWithTenants() {
// If the node was already included in the moveSequence, skip it.
if moveSequence.hasNode(n) {
continue
Expand Down Expand Up @@ -360,7 +360,7 @@ func patchCluster(proxy Proxy, cluster *node, patch client.Patch) error {
func (o *objectMover) ensureNamespaces(graph *objectGraph, toProxy Proxy) error {
ensureNamespaceBackoff := newWriteBackoff()
namespaces := sets.NewString()
for _, node := range graph.getNodesWithClusterTenants() {
for _, node := range graph.getNodesWithTenants() {
namespace := node.identity.Namespace

// If the namespace was already processed, skip it.
Expand Down
36 changes: 36 additions & 0 deletions cmd/clusterctl/client/cluster/mover_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,42 @@ var moveTests = []struct {
},
},
},
{
name: "A ClusterResourceSet applied to a cluster",
fields: moveTestsFields{
objs: func() []runtime.Object {
objs := []runtime.Object{}
objs = append(objs, test.NewFakeCluster("ns1", "cluster1").Objs()...)

objs = append(objs, test.NewFakeClusterResourceSet("ns1", "crs1").
WithSecret("resource-s1").
WithConfigMap("resource-c1").
ApplyToCluster(test.SelectClusterObj(objs, "ns1", "cluster1")).
Objs()...)

return objs
}(),
},
wantMoveGroups: [][]string{
{ //group 1
// Cluster
"cluster.x-k8s.io/v1alpha3, Kind=Cluster, ns1/cluster1",
// ClusterResourceSet
"addons.cluster.x-k8s.io/v1alpha3, Kind=ClusterResourceSet, ns1/crs1",
},
{ //group 2 (objects with ownerReferences in group 1)
// owned by Clusters
"/v1, Kind=Secret, ns1/cluster1-ca",
"/v1, Kind=Secret, ns1/cluster1-kubeconfig",
"infrastructure.cluster.x-k8s.io/v1alpha3, Kind=GenericInfrastructureCluster, ns1/cluster1",
// owned by ClusterResourceSet
"/v1, Kind=Secret, ns1/resource-s1",
"/v1, Kind=ConfigMap, ns1/resource-c1",
// owned by ClusterResourceSet & Cluster
"addons.cluster.x-k8s.io/v1alpha3, Kind=ClusterResourceSetBinding, ns1/crs1",
},
},
},
}

func Test_getMoveSequence(t *testing.T) {
Expand Down
46 changes: 42 additions & 4 deletions cmd/clusterctl/client/cluster/objectgraph.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha3"
clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
logf "sigs.k8s.io/cluster-api/cmd/clusterctl/log"
addonsv1alpha3 "sigs.k8s.io/cluster-api/exp/addons/api/v1alpha3"
secretutil "sigs.k8s.io/cluster-api/util/secret"
"sigs.k8s.io/controller-runtime/pkg/client"
)
Expand Down Expand Up @@ -58,6 +59,10 @@ type node struct {
// tenantClusters define the list of Clusters which are tenant for the node, no matter if the node has a direct OwnerReference to the Cluster or if
// the node is linked to a Cluster indirectly in the OwnerReference chain.
tenantClusters map[*node]empty

// tenantCRSs define the list of ClusterResourceSet which are tenant for the node, no matter if the node has a direct OwnerReference to the ClusterResourceSet or if
// the node is linked to a ClusterResourceSet indirectly in the OwnerReference chain.
tenantCRSs map[*node]empty
}

// markObserved marks the fact that a node was observed as a concrete object.
Expand Down Expand Up @@ -130,6 +135,7 @@ func (o *objectGraph) ownerToVirtualNode(owner metav1.OwnerReference, namespace
owners: make(map[*node]ownerReferenceAttributes),
softOwners: make(map[*node]empty),
tenantClusters: make(map[*node]empty),
tenantCRSs: make(map[*node]empty),
virtual: true,
}

Expand Down Expand Up @@ -158,6 +164,7 @@ func (o *objectGraph) objToNode(obj *unstructured.Unstructured) *node {
owners: make(map[*node]ownerReferenceAttributes),
softOwners: make(map[*node]empty),
tenantClusters: make(map[*node]empty),
tenantCRSs: make(map[*node]empty),
virtual: false,
}

Expand Down Expand Up @@ -254,6 +261,9 @@ func (o *objectGraph) Discovery(namespace string, types []metav1.TypeMeta) error
// Completes the graph by setting for each node the list of Clusters the node belong to.
o.setClusterTenants()

// Completes the graph by setting for each node the list of ClusterResourceSet the node belong to.
o.setCRSTenants()

return nil
}

Expand Down Expand Up @@ -306,11 +316,22 @@ func (o *objectGraph) getNodes() []*node {
return nodes
}

// getNodesWithClusterTenants returns the list of nodes existing in the object graph that belong at least to one Cluster.
func (o *objectGraph) getNodesWithClusterTenants() []*node {
// getCRSs returns the list of ClusterResourceSet existing in the object graph.
func (o *objectGraph) getCRSs() []*node {
clusters := []*node{}
for _, node := range o.uidToNode {
if node.identity.GroupVersionKind().GroupKind() == addonsv1alpha3.GroupVersion.WithKind("ClusterResourceSet").GroupKind() {
clusters = append(clusters, node)
}
}
return clusters
}

// getNodesWithTenants returns the list of nodes existing in the object graph that belong at least to one Cluster or to a ClusterResourceSet.
func (o *objectGraph) getNodesWithTenants() []*node {
nodes := []*node{}
for _, node := range o.uidToNode {
if len(node.tenantClusters) > 0 {
if len(node.tenantClusters) > 0 || len(node.tenantCRSs) > 0 {
nodes = append(nodes, node)
}
}
Expand Down Expand Up @@ -360,7 +381,7 @@ func (o *objectGraph) setClusterTenants() {
}
}

// setNodeTenant sets a tenant for a node and for its own dependents/sofDependents.
// setNodeTenant sets a cluster tenant for a node and for its own dependents/sofDependents.
func (o *objectGraph) setClusterTenant(node, tenant *node) {
node.tenantClusters[tenant] = empty{}
for _, other := range o.getNodes() {
Expand All @@ -369,3 +390,20 @@ func (o *objectGraph) setClusterTenant(node, tenant *node) {
}
}
}

// setClusterTenants sets the ClusterResourceSet tenants for the ClusterResourceSet itself and all their dependent object tree.
func (o *objectGraph) setCRSTenants() {
for _, crs := range o.getCRSs() {
o.setCRSTenant(crs, crs)
}
}

// setCRSTenant sets a ClusterResourceSet tenant for a node and for its own dependents/sofDependents.
func (o *objectGraph) setCRSTenant(node, tenant *node) {
node.tenantCRSs[tenant] = empty{}
for _, other := range o.getNodes() {
if other.isOwnedBy(node) {
o.setCRSTenant(other, tenant)
}
}
}
Loading