Skip to content

Commit

Permalink
Merge pull request #8836 from Jont828/mpm-clusterctl
Browse files Browse the repository at this point in the history
✨ Add MachinePool Machine support in clusterctl discovery
  • Loading branch information
k8s-ci-robot authored Jul 10, 2023
2 parents da10c33 + 378d6a4 commit 1fecd9f
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 41 deletions.
4 changes: 4 additions & 0 deletions api/v1beta1/machine_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ const (
// MachineDeploymentNameLabel is the label set on machines if they're controlled by MachineDeployment.
MachineDeploymentNameLabel = "cluster.x-k8s.io/deployment-name"

// MachinePoolNameLabel is the label indicating the name of the MachinePool a Machine is controlled by.
// Note: The value of this label may be a hash if the MachinePool name is longer than 63 characters.
MachinePoolNameLabel = "cluster.x-k8s.io/pool-name"

// MachineControlPlaneNameLabel is the label set on machines if they're controlled by a ControlPlane.
// Note: The value of this label may be a hash if the control plane name is longer than 63 characters.
MachineControlPlaneNameLabel = "cluster.x-k8s.io/control-plane-name"
Expand Down
53 changes: 31 additions & 22 deletions cmd/clusterctl/client/tree/discovery.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,12 +111,16 @@ func Discovery(ctx context.Context, c client.Client, namespace, name string, opt
machineMap[m.Name] = true

if visible {
if machineInfra, err := external.Get(ctx, c, &m.Spec.InfrastructureRef, cluster.Namespace); err == nil {
tree.Add(m, machineInfra, ObjectMetaName("MachineInfrastructure"), NoEcho(true))
if (m.Spec.InfrastructureRef != corev1.ObjectReference{}) {
if machineInfra, err := external.Get(ctx, c, &m.Spec.InfrastructureRef, cluster.Namespace); err == nil {
tree.Add(m, machineInfra, ObjectMetaName("MachineInfrastructure"), NoEcho(true))
}
}

if machineBootstrap, err := external.Get(ctx, c, m.Spec.Bootstrap.ConfigRef, cluster.Namespace); err == nil {
tree.Add(m, machineBootstrap, ObjectMetaName("BootstrapConfig"), NoEcho(true))
if m.Spec.Bootstrap.ConfigRef != nil {
if machineBootstrap, err := external.Get(ctx, c, m.Spec.Bootstrap.ConfigRef, cluster.Namespace); err == nil {
tree.Add(m, machineBootstrap, ObjectMetaName("BootstrapConfig"), NoEcho(true))
}
}
}
}
Expand Down Expand Up @@ -146,25 +150,25 @@ func Discovery(ctx context.Context, c client.Client, namespace, name string, opt
if err != nil {
return nil, err
}

// Handles orphan machines.
if len(machineMap) < len(machinesList.Items) {
other := VirtualObject(cluster.Namespace, "OtherGroup", "Other")
tree.Add(workers, other)

for i := range machinesList.Items {
m := &machinesList.Items[i]
if _, ok := machineMap[m.Name]; ok {
continue
}
addMachineFunc(other, m)
}
}
}

if len(machinePoolList.Items) > 0 { // Add MachinePool objects
tree.Add(cluster, workers)
addMachinePoolsToObjectTree(ctx, c, cluster.Namespace, workers, machinePoolList, tree)
addMachinePoolsToObjectTree(ctx, c, cluster.Namespace, workers, machinePoolList, machinesList, tree, addMachineFunc)
}

// Handles orphan machines.
if len(machineMap) < len(machinesList.Items) {
other := VirtualObject(cluster.Namespace, "OtherGroup", "Other")
tree.Add(workers, other)

for i := range machinesList.Items {
m := &machinesList.Items[i]
if _, ok := machineMap[m.Name]; ok {
continue
}
addMachineFunc(other, m)
}
}

return tree, nil
Expand Down Expand Up @@ -271,20 +275,25 @@ func addMachineDeploymentToObjectTree(ctx context.Context, c client.Client, clus
return nil
}

func addMachinePoolsToObjectTree(ctx context.Context, c client.Client, namespace string, workers *unstructured.Unstructured, machinePoolList *expv1.MachinePoolList, tree *ObjectTree) {
func addMachinePoolsToObjectTree(ctx context.Context, c client.Client, namespace string, workers *unstructured.Unstructured, machinePoolList *expv1.MachinePoolList, machinesList *clusterv1.MachineList, tree *ObjectTree, addMachineFunc func(parent client.Object, m *clusterv1.Machine)) {
for i := range machinePoolList.Items {
mp := &machinePoolList.Items[i]
_, visible := tree.Add(workers, mp)
_, visible := tree.Add(workers, mp, GroupingObject(true))

if visible {
if machinePoolBootstrap, err := external.Get(ctx, c, mp.Spec.Template.Spec.Bootstrap.ConfigRef, namespace); err == nil {
tree.Add(mp, machinePoolBootstrap, ObjectMetaName("BootstrapConfig"), NoEcho(true))
}

if machinePoolInfra, err := external.Get(ctx, c, &mp.Spec.Template.Spec.InfrastructureRef, namespace); err == nil {
tree.Add(mp, machinePoolInfra, ObjectMetaName("MachineInfrastructure"), NoEcho(true))
tree.Add(mp, machinePoolInfra, ObjectMetaName("MachinePoolInfrastructure"), NoEcho(true))
}
}

machines := selectMachinesControlledBy(machinesList, mp)
for _, m := range machines {
addMachineFunc(mp, m)
}
}
}

Expand Down
80 changes: 80 additions & 0 deletions cmd/clusterctl/client/tree/discovery_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,86 @@ func Test_Discovery(t *testing.T) {
},
},
},
{
name: "Discovery with MachinePool Machines with echo enabled",
args: args{
discoverOptions: DiscoverOptions{
Grouping: false,
Echo: true,
},
objs: test.NewFakeCluster("ns1", "cluster1").
WithControlPlane(
test.NewFakeControlPlane("cp").
WithMachines(
test.NewFakeMachine("cp1"),
),
).
WithMachinePools(
test.NewFakeMachinePool("mp1").
WithMachines(
test.NewFakeMachine("mp1m1"),
test.NewFakeMachine("mp1m2"),
),
).
Objs(),
},
wantTree: map[string][]string{
// Cluster should be parent of InfrastructureCluster, ControlPlane, and WorkerNodes
"cluster.x-k8s.io/v1beta1, Kind=Cluster, ns1/cluster1": {
"infrastructure.cluster.x-k8s.io/v1beta1, Kind=GenericInfrastructureCluster, ns1/cluster1",
"controlplane.cluster.x-k8s.io/v1beta1, Kind=GenericControlPlane, ns1/cp",
"virtual.cluster.x-k8s.io/v1beta1, Kind=WorkerGroup, ns1/Workers",
},
// InfrastructureCluster should be leaf
"infrastructure.cluster.x-k8s.io/v1beta1, Kind=GenericInfrastructureCluster, ns1/cluster1": {},
// ControlPlane should have a machine
"controlplane.cluster.x-k8s.io/v1beta1, Kind=GenericControlPlane, ns1/cp": {
"cluster.x-k8s.io/v1beta1, Kind=Machine, ns1/cp1",
},
// Workers should have a machine deployment
"virtual.cluster.x-k8s.io/v1beta1, Kind=WorkerGroup, ns1/Workers": {
"cluster.x-k8s.io/v1beta1, Kind=MachinePool, ns1/mp1",
},
// Machine Pool should have a group of machines
"cluster.x-k8s.io/v1beta1, Kind=MachinePool, ns1/mp1": {
"infrastructure.cluster.x-k8s.io/v1beta1, Kind=GenericInfrastructureMachineTemplate, ns1/mp1",
"bootstrap.cluster.x-k8s.io/v1beta1, Kind=GenericBootstrapConfigTemplate, ns1/mp1",
"cluster.x-k8s.io/v1beta1, Kind=Machine, ns1/mp1m1",
"cluster.x-k8s.io/v1beta1, Kind=Machine, ns1/mp1m2",
},
// Machine should have infra machine and bootstrap (echo)
"cluster.x-k8s.io/v1beta1, Kind=Machine, ns1/cp1": {
"infrastructure.cluster.x-k8s.io/v1beta1, Kind=GenericInfrastructureMachine, ns1/cp1",
"bootstrap.cluster.x-k8s.io/v1beta1, Kind=GenericBootstrapConfig, ns1/cp1",
},
// MachinePool Machine should only have infra machine
"cluster.x-k8s.io/v1beta1, Kind=Machine, ns1/mp1m1": {
"infrastructure.cluster.x-k8s.io/v1beta1, Kind=GenericInfrastructureMachine, ns1/mp1m1",
},
"cluster.x-k8s.io/v1beta1, Kind=Machine, ns1/mp1m2": {
"infrastructure.cluster.x-k8s.io/v1beta1, Kind=GenericInfrastructureMachine, ns1/mp1m2",
},
},
wantNodeCheck: map[string]nodeCheck{
// InfrastructureCluster should have a meta name
"infrastructure.cluster.x-k8s.io/v1beta1, Kind=GenericInfrastructureCluster, ns1/cluster1": func(g *WithT, obj client.Object) {
g.Expect(GetMetaName(obj)).To(Equal("ClusterInfrastructure"))
},
// ControlPlane should have a meta name, should NOT be a grouping object
"controlplane.cluster.x-k8s.io/v1beta1, Kind=GenericControlPlane, ns1/cp": func(g *WithT, obj client.Object) {
g.Expect(GetMetaName(obj)).To(Equal("ControlPlane"))
g.Expect(IsGroupingObject(obj)).To(BeFalse())
},
// Workers should be a virtual node
"virtual.cluster.x-k8s.io/v1beta1, Kind=WorkerGroup, ns1/Workers": func(g *WithT, obj client.Object) {
g.Expect(IsVirtualObject(obj)).To(BeTrue())
},
// Machine pool should NOT be a grouping object
"cluster.x-k8s.io/v1beta1, Kind=MachinePool, ns1/mp1": func(g *WithT, obj client.Object) {
g.Expect(IsGroupingObject(obj)).To(BeFalse())
},
},
},
{
name: "Discovery with grouping and no-echo disabled",
args: args{
Expand Down
54 changes: 35 additions & 19 deletions cmd/clusterctl/internal/test/fake_objects.go
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ func (f *FakeCluster) Objs() []client.Object {
if f.controlPlane == nil && i == 0 {
generateCerts = true
}
objs = append(objs, machine.Objs(cluster, generateCerts, nil, nil)...)
objs = append(objs, machine.Objs(cluster, generateCerts, nil, nil, nil)...)
}

// Ensure all the objects gets UID.
Expand Down Expand Up @@ -403,7 +403,7 @@ func (f *FakeControlPlane) Objs(cluster *clusterv1.Cluster) []client.Object {

// Adds the objects for the machines controlled by the controlPlane
for _, machine := range f.machines {
objs = append(objs, machine.Objs(cluster, false, nil, controlPlane)...)
objs = append(objs, machine.Objs(cluster, false, nil, nil, controlPlane)...)
}

return objs
Expand All @@ -412,6 +412,7 @@ func (f *FakeControlPlane) Objs(cluster *clusterv1.Cluster) []client.Object {
type FakeMachinePool struct {
name string
bootstrapConfig *clusterv1.Bootstrap
machines []*FakeMachine
}

// NewFakeMachinePool return a FakeMachinePool that can generate a MachinePool object, all its own ancillary objects:
Expand All @@ -428,6 +429,11 @@ func (f *FakeMachinePool) WithStaticBootstrapConfig() *FakeMachinePool {
return f
}

func (f *FakeMachinePool) WithMachines(fakeMachine ...*FakeMachine) *FakeMachinePool {
f.machines = append(f.machines, fakeMachine...)
return f
}

func (f *FakeMachinePool) Objs(cluster *clusterv1.Cluster) []client.Object {
machinePoolInfrastructure := &fakeinfrastructure.GenericInfrastructureMachineTemplate{
TypeMeta: metav1.TypeMeta{
Expand Down Expand Up @@ -523,6 +529,10 @@ func (f *FakeMachinePool) Objs(cluster *clusterv1.Cluster) []client.Object {
objs = append(objs, machinePoolBootstrap)
}

for _, machine := range f.machines {
objs = append(objs, machine.Objs(cluster, false, nil, machinePool, nil)...)
}

return objs
}

Expand Down Expand Up @@ -847,7 +857,7 @@ func (f *FakeMachineSet) Objs(cluster *clusterv1.Cluster, machineDeployment *clu

// Adds the objects for the machines controlled by the machineSet
for _, machine := range f.machines {
objs = append(objs, machine.Objs(cluster, false, machineSet, nil)...)
objs = append(objs, machine.Objs(cluster, false, machineSet, nil, nil)...)
}

return objs
Expand All @@ -873,7 +883,7 @@ func (f *FakeMachine) WithStaticBootstrapConfig() *FakeMachine {
return f
}

func (f *FakeMachine) Objs(cluster *clusterv1.Cluster, generateCerts bool, machineSet *clusterv1.MachineSet, controlPlane *fakecontrolplane.GenericControlPlane) []client.Object {
func (f *FakeMachine) Objs(cluster *clusterv1.Cluster, generateCerts bool, machineSet *clusterv1.MachineSet, machinePool *expv1.MachinePool, controlPlane *fakecontrolplane.GenericControlPlane) []client.Object {
machineInfrastructure := &fakeinfrastructure.GenericInfrastructureMachine{
TypeMeta: metav1.TypeMeta{
APIVersion: fakeinfrastructure.GroupVersion.String(),
Expand Down Expand Up @@ -955,8 +965,6 @@ func (f *FakeMachine) Objs(cluster *clusterv1.Cluster, generateCerts bool, machi
},
}

machine.Spec.Bootstrap = *bootstrapConfig

// Ensure the machine gets a UID to be used by dependant objects for creating OwnerReferences.
setUID(machine)

Expand All @@ -971,6 +979,11 @@ func (f *FakeMachine) Objs(cluster *clusterv1.Cluster, generateCerts bool, machi
machine.SetOwnerReferences([]metav1.OwnerReference{*metav1.NewControllerRef(controlPlane, controlPlane.GroupVersionKind())})
// Sets the MachineControlPlane Label
machine.Labels[clusterv1.MachineControlPlaneLabel] = ""
case machinePool != nil:
// If this machine belong to a machinePool, it is controlled by it / ownership set by the machinePool controller -- ** NOT RECONCILED **
machine.SetOwnerReferences([]metav1.OwnerReference{*metav1.NewControllerRef(machinePool, machinePool.GroupVersionKind())})
// Sets the MachinePoolNameLabel
machine.Labels[clusterv1.MachinePoolNameLabel] = machinePool.Name
default:
// If this machine does not belong to a machineSet or to a control plane, it is owned by the cluster / ownership set by the machine controller -- RECONCILED
machine.SetOwnerReferences([]metav1.OwnerReference{{
Expand Down Expand Up @@ -1017,20 +1030,23 @@ func (f *FakeMachine) Objs(cluster *clusterv1.Cluster, generateCerts bool, machi
machineInfrastructure,
}

if machine.Spec.Bootstrap.ConfigRef != nil {
machineBootstrap.SetOwnerReferences([]metav1.OwnerReference{
{
APIVersion: machine.APIVersion,
Kind: machine.Kind,
Name: machine.Name,
UID: machine.UID,
},
})
machineBootstrap.SetLabels(map[string]string{
clusterv1.ClusterNameLabel: machine.Spec.ClusterName,
})
if machinePool == nil {
machine.Spec.Bootstrap = *bootstrapConfig
if machine.Spec.Bootstrap.ConfigRef != nil {
machineBootstrap.SetOwnerReferences([]metav1.OwnerReference{
{
APIVersion: machine.APIVersion,
Kind: machine.Kind,
Name: machine.Name,
UID: machine.UID,
},
})
machineBootstrap.SetLabels(map[string]string{
clusterv1.ClusterNameLabel: machine.Spec.ClusterName,
})

objs = append(objs, bootstrapDataSecret, machineBootstrap)
objs = append(objs, bootstrapDataSecret, machineBootstrap)
}
}

objs = append(objs, additionalObjs...)
Expand Down

0 comments on commit 1fecd9f

Please sign in to comment.