Skip to content
Open
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
22 changes: 22 additions & 0 deletions cmd/clusterctl/clusterdeployer/clusterclient/clusterclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -1057,3 +1057,25 @@ func ExtractControlPlaneMachines(machines []*clusterv1.Machine) ([]*clusterv1.Ma
}
return controlPlaneMachines, nodes, nil
}

// ExtractControlPlaneMachineDeployments separates machinedeployments defining control plane machines from those defining nodes.
// This is currently done by looking at which machinedeployments specify machine templates with a control plane version
func ExtractControlPlaneMachineDeployments(machineDeployments []*clusterv1.MachineDeployment) (*clusterv1.MachineDeployment, []*clusterv1.MachineDeployment, error) {
nodeDeployments := []*clusterv1.MachineDeployment{}
controlPlaneDeployments := []*clusterv1.MachineDeployment{}
for _, machineDeployment := range machineDeployments {
if util.IsControlPlaneMachineDeployment(machineDeployment) {
controlPlaneDeployments = append(controlPlaneDeployments, machineDeployment)
} else {
nodeDeployments = append(nodeDeployments, machineDeployment)
}
}

if len(controlPlaneDeployments) > 1 {
return nil, nil, errors.Errorf("expected one or zero control plane machinedeployments, got: %v", len(controlPlaneDeployments))
} else if len(controlPlaneDeployments) == 1 {
return controlPlaneDeployments[0], nodeDeployments, nil
}

return nil, nodeDeployments, nil
}
13 changes: 9 additions & 4 deletions cmd/clusterctl/clusterdeployer/clusterdeployer.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func New(
}

// Create the cluster from the provided cluster definition and machine list.
func (d *ClusterDeployer) Create(cluster *clusterv1.Cluster, machines []*clusterv1.Machine, provider provider.Deployer, kubeconfigOutput string, providerComponentsStoreFactory provider.ComponentsStoreFactory) error {
func (d *ClusterDeployer) Create(cluster *clusterv1.Cluster, machines []*clusterv1.Machine, machineDeployments []*clusterv1.MachineDeployment, provider provider.Deployer, kubeconfigOutput string, providerComponentsStoreFactory provider.ComponentsStoreFactory) error {
controlPlaneMachines, nodes, err := clusterclient.ExtractControlPlaneMachines(machines)
if err != nil {
return errors.Wrap(err, "unable to separate control plane machines from node machines")
Expand Down Expand Up @@ -90,7 +90,7 @@ func (d *ClusterDeployer) Create(cluster *clusterv1.Cluster, machines []*cluster
}

klog.Infof("Creating control plane %v in namespace %q", controlPlaneMachines[0].Name, cluster.Namespace)
if err := phases.ApplyMachines(bootstrapClient, cluster.Namespace, []*clusterv1.Machine{controlPlaneMachines[0]}); err != nil {
if err := phases.ApplyMachines(bootstrapClient, cluster.Namespace, []*clusterv1.Machine{controlPlaneMachines[0]}, []*clusterv1.MachineDeployment{}); err != nil {
return errors.Wrap(err, "unable to create control plane machine")
}

Expand Down Expand Up @@ -140,14 +140,19 @@ func (d *ClusterDeployer) Create(cluster *clusterv1.Cluster, machines []*cluster
// supported versions of k8s we are deploying (using kubeadm) have the fix.
klog.Info("Creating additional control plane machines in target cluster.")
for _, controlPlaneMachine := range controlPlaneMachines[1:] {
if err := phases.ApplyMachines(targetClient, cluster.Namespace, []*clusterv1.Machine{controlPlaneMachine}); err != nil {
if err := phases.ApplyMachines(targetClient, cluster.Namespace, []*clusterv1.Machine{controlPlaneMachine}, []*clusterv1.MachineDeployment{}); err != nil {
return errors.Wrap(err, "unable to create additional control plane machines")
}
}
}

_, nodeDeployments, err := clusterclient.ExtractControlPlaneMachineDeployments(machineDeployments)
if err != nil {
return errors.Wrap(err, "unable to separate control plane machineDeployments from node machineDeployments")
}

klog.Info("Creating node machines in target cluster.")
if err := phases.ApplyMachines(targetClient, cluster.Namespace, nodes); err != nil {
if err := phases.ApplyMachines(targetClient, cluster.Namespace, nodes, nodeDeployments); err != nil {
return errors.Wrap(err, "unable to create node machines")
}

Expand Down
148 changes: 144 additions & 4 deletions cmd/clusterctl/clusterdeployer/clusterdeployer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -849,6 +849,7 @@ func TestClusterCreate(t *testing.T) {
d := New(p, f, "", "", bootstrapComponent, testcase.cleanupExternal)

inputMachines := make(map[string][]*clusterv1.Machine)
inputMachineDeployments := make(map[string][]*clusterv1.MachineDeployment)

for namespace, inputClusters := range testcase.namespaceToInputCluster {
ns := namespace
Expand All @@ -860,7 +861,9 @@ func TestClusterCreate(t *testing.T) {
for _, inputCluster := range inputClusters {
inputCluster.Name = fmt.Sprintf("%s-cluster", ns)
inputMachines[inputCluster.Name] = generateMachines(inputCluster, ns)
err = d.Create(inputCluster, inputMachines[inputCluster.Name], pd, kubeconfigOut, &pcFactory)
inputMachineDeployments[inputCluster.Name] = generateMachineDeployments(inputCluster, ns)

err = d.Create(inputCluster, inputMachines[inputCluster.Name], inputMachineDeployments[inputCluster.Name], pd, kubeconfigOut, &pcFactory)
if err != nil {
break
}
Expand Down Expand Up @@ -958,11 +961,12 @@ func TestCreateProviderComponentsScenarios(t *testing.T) {
},
}
inputMachines := generateMachines(inputCluster, metav1.NamespaceDefault)
inputMachineDeployments := generateMachineDeployments(inputCluster, metav1.NamespaceDefault)
pcFactory := mockProviderComponentsStoreFactory{NewFromCoreclientsetPCStore: &tc.pcStore}
providerComponentsYaml := "---\nyaml: definition"
addonsYaml := "---\nyaml: definition"
d := New(p, f, providerComponentsYaml, addonsYaml, "", false)
err := d.Create(inputCluster, inputMachines, pd, kubeconfigOut, &pcFactory)
err := d.Create(inputCluster, inputMachines, inputMachineDeployments, pd, kubeconfigOut, &pcFactory)
if err == nil && tc.expectedError != "" {
t.Fatalf("error mismatch: got '%v', want '%v'", err, tc.expectedError)
}
Expand Down Expand Up @@ -1049,6 +1053,65 @@ func TestExtractControlPlaneMachine(t *testing.T) {
}
}

func TestExtractControlPlaneMachineDeployments(t *testing.T) {
const singleControlPlaneName = "test-control-plane"
multipleControlPlaneNames := []string{"test-control-plane-1", "test-control-plane-2"}
const singleNodeDeploymentName = "test-nodes"
multipleNodeDeploymentNames := []string{"test-nodes-1", "test-nodes-2", "test-nodes-3"}

testCases := []struct {
name string
inputMachineDeployments []*clusterv1.MachineDeployment
expectedControlPlane *clusterv1.MachineDeployment
expectedNodes []*clusterv1.MachineDeployment
expectedError error
}{
{
name: "success_1_control_plane_1_node",
inputMachineDeployments: generateMachineDeployments(nil, metav1.NamespaceDefault),
expectedControlPlane: generateTestControlPlaneMachineDeployment(nil, metav1.NamespaceDefault, singleControlPlaneName),
expectedNodes: generateTestNodeMachineDeployments(nil, metav1.NamespaceDefault, []string{singleNodeDeploymentName}),
expectedError: nil,
},
{
name: "success_1_control_plane_multiple_nodes",
inputMachineDeployments: generateValidExtractControlPlaneMachineDeploymentInput(nil, metav1.NamespaceDefault, singleControlPlaneName, multipleNodeDeploymentNames),
expectedControlPlane: generateTestControlPlaneMachineDeployment(nil, metav1.NamespaceDefault, singleControlPlaneName),
expectedNodes: generateTestNodeMachineDeployments(nil, metav1.NamespaceDefault, multipleNodeDeploymentNames),
expectedError: nil,
},
{
name: "fail_more_than_1_control_plane_not_allowed",
inputMachineDeployments: generateInvalidExtractControlPlaneMachineDeployment(nil, metav1.NamespaceDefault, multipleControlPlaneNames, multipleNodeDeploymentNames),
expectedControlPlane: nil,
expectedNodes: nil,
expectedError: errors.New("expected one or zero control plane machinedeployments, got: 2"),
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
actualControlPlane, actualNodes, actualError := clusterclient.ExtractControlPlaneMachineDeployments(tc.inputMachineDeployments)

if tc.expectedError == nil && actualError != nil {
t.Fatalf("%s: extractControlPlaneMachine(%q): gotError %q; wantError [nil]", tc.name, len(tc.inputMachineDeployments), actualError)
}

if tc.expectedError != nil && tc.expectedError.Error() != actualError.Error() {
t.Fatalf("%s: extractControlPlaneMachine(%q): gotError %q; wantError %q", tc.name, len(tc.inputMachineDeployments), actualError, tc.expectedError)
}

if (tc.expectedControlPlane == nil && actualControlPlane != nil) ||
(tc.expectedControlPlane != nil && actualControlPlane == nil) {
t.Fatalf("%s: extractControlPlaneMachine(%q): gotControlPlane = %v; wantControlPlane = %v", tc.name, len(tc.inputMachineDeployments), actualControlPlane != nil, tc.expectedControlPlane != nil)
}

if len(tc.expectedNodes) != len(actualNodes) {
t.Fatalf("%s: extractControlPlaneMachine(%q): gotNodes = %q; wantNodes = %q", tc.name, len(tc.inputMachineDeployments), len(actualNodes), len(tc.expectedNodes))
}
})
}
}

func TestDeleteCleanupExternalCluster(t *testing.T) {
const bootstrapKubeconfig = "bootstrap"
const targetKubeconfig = "target"
Expand Down Expand Up @@ -1444,6 +1507,16 @@ func generateTestControlPlaneMachines(cluster *clusterv1.Cluster, ns string, nam
return machines
}

func generateTestControlPlaneMachineDeployment(cluster *clusterv1.Cluster, ns, name string) *clusterv1.MachineDeployment {
machineDeployment := generateTestNodeMachineDeployment(cluster, ns, name)
machineDeployment.Spec.Template.Spec = clusterv1.MachineSpec{
Versions: clusterv1.MachineVersionInfo{
ControlPlane: "1.10.1",
},
}
return machineDeployment
}

func generateTestNodeMachine(cluster *clusterv1.Cluster, ns, name string) *clusterv1.Machine {
machine := clusterv1.Machine{
ObjectMeta: metav1.ObjectMeta{
Expand All @@ -1465,6 +1538,27 @@ func generateTestNodeMachine(cluster *clusterv1.Cluster, ns, name string) *clust
return &machine
}

func generateTestNodeMachineDeployment(cluster *clusterv1.Cluster, ns, name string) *clusterv1.MachineDeployment {
machineDeployment := clusterv1.MachineDeployment{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: ns,
},
}
if cluster != nil {
machineDeployment.Labels = map[string]string{clusterv1.MachineClusterLabelName: cluster.Name}
machineDeployment.OwnerReferences = []metav1.OwnerReference{
{
APIVersion: cluster.APIVersion,
Kind: cluster.Kind,
Name: cluster.Name,
UID: cluster.UID,
},
}
}
return &machineDeployment
}

func generateTestNodeMachines(cluster *clusterv1.Cluster, ns string, nodeNames []string) []*clusterv1.Machine {
nodes := make([]*clusterv1.Machine, 0, len(nodeNames))
for _, nn := range nodeNames {
Expand All @@ -1473,13 +1567,46 @@ func generateTestNodeMachines(cluster *clusterv1.Cluster, ns string, nodeNames [
return nodes
}

func generateValidExtractControlPlaneMachineInput(cluster *clusterv1.Cluster, ns string, controlPlaneName []string, nodeNames []string) []*clusterv1.Machine {
func generateTestNodeMachineDeployments(cluster *clusterv1.Cluster, ns string, nodeDeploymentNames []string) []*clusterv1.MachineDeployment {
nodeDeployments := make([]*clusterv1.MachineDeployment, 0, len(nodeDeploymentNames))
for _, ndn := range nodeDeploymentNames {
nodeDeployments = append(nodeDeployments, generateTestNodeMachineDeployment(cluster, ns, ndn))
}
return nodeDeployments
}

func generateInvalidExtractControlPlaneMachine(cluster *clusterv1.Cluster, ns string, controlPlaneNames, nodeNames []string) []*clusterv1.Machine {
var machines []*clusterv1.Machine // nolint
for _, name := range controlPlaneNames {
machines = append(machines, generateTestControlPlaneMachines(cluster, ns, []string{name})...)
}
machines = append(machines, generateTestNodeMachines(cluster, ns, nodeNames)...)
return machines
}

func generateValidExtractControlPlaneMachineInput(cluster *clusterv1.Cluster, ns string, controlPlaneNames, nodeNames []string) []*clusterv1.Machine {
var machines []*clusterv1.Machine
machines = append(machines, generateTestControlPlaneMachines(cluster, ns, controlPlaneName)...)
machines = append(machines, generateTestControlPlaneMachines(cluster, ns, controlPlaneNames)...)
machines = append(machines, generateTestNodeMachines(cluster, ns, nodeNames)...)
return machines
}

func generateInvalidExtractControlPlaneMachineDeployment(cluster *clusterv1.Cluster, ns string, controlPlaneNames, nodeDeploymentNames []string) []*clusterv1.MachineDeployment {
var machineDeployments []*clusterv1.MachineDeployment
for _, name := range controlPlaneNames {
machineDeployments = append(machineDeployments, generateTestControlPlaneMachineDeployment(cluster, ns, name))
}
machineDeployments = append(machineDeployments, generateTestNodeMachineDeployments(cluster, ns, nodeDeploymentNames)...)
return machineDeployments
}

func generateValidExtractControlPlaneMachineDeploymentInput(cluster *clusterv1.Cluster, ns, controlPlaneName string, nodeDeploymentNames []string) []*clusterv1.MachineDeployment {
var machineDeployments []*clusterv1.MachineDeployment
machineDeployments = append(machineDeployments, generateTestControlPlaneMachineDeployment(cluster, ns, controlPlaneName))
machineDeployments = append(machineDeployments, generateTestNodeMachineDeployments(cluster, ns, nodeDeploymentNames)...)
return machineDeployments
}

func generateMachines(cluster *clusterv1.Cluster, ns string) []*clusterv1.Machine {
var machines []*clusterv1.Machine
controlPlaneName := "control-plane"
Expand All @@ -1493,6 +1620,19 @@ func generateMachines(cluster *clusterv1.Cluster, ns string) []*clusterv1.Machin
return machines
}

func generateMachineDeployments(cluster *clusterv1.Cluster, ns string) []*clusterv1.MachineDeployment {
var machineDeployments []*clusterv1.MachineDeployment
controlPlaneName := "control-plane"
nodeDeploymentName := "node-deployment"
if cluster != nil {
controlPlaneName = cluster.Name + controlPlaneName
nodeDeploymentName = cluster.Name + nodeDeploymentName
}
machineDeployments = append(machineDeployments, generateTestControlPlaneMachineDeployment(cluster, ns, controlPlaneName))
machineDeployments = append(machineDeployments, generateTestNodeMachineDeployment(cluster, ns, nodeDeploymentName))
return machineDeployments
}

func newMachineSetsFixture(ns string) []*clusterv1.MachineSet {
return []*clusterv1.MachineSet{
{ObjectMeta: metav1.ObjectMeta{Name: "machine-set-name-1", Namespace: ns}},
Expand Down
7 changes: 6 additions & 1 deletion cmd/clusterctl/cmd/alpha_phase_apply_machines.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,18 @@ func RunAlphaPhaseApplyMachines(pamo *AlphaPhaseApplyMachinesOptions) error {
return err
}

machineDeployments, err := util.ParseMachineDeploymentYaml(pamo.Machines)
if err != nil {
return err
}

clientFactory := clusterclient.NewFactory()
client, err := clientFactory.NewClientFromKubeconfig(string(kubeconfig))
if err != nil {
return errors.Wrap(err, "unable to create cluster client")
}

if err := phases.ApplyMachines(client, pamo.Namespace, machines); err != nil {
if err := phases.ApplyMachines(client, pamo.Namespace, machines, machineDeployments); err != nil {
return errors.Wrap(err, "unable to apply machines")
}

Expand Down
6 changes: 5 additions & 1 deletion cmd/clusterctl/cmd/create_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ func RunCreate(co *CreateOptions) error {
if err != nil {
return err
}
md, err := util.ParseMachineDeploymentYaml(co.Machine)
if err != nil {
return err
}

bootstrapProvider, err := bootstrap.Get(co.BootstrapFlags)
if err != nil {
Expand Down Expand Up @@ -109,7 +113,7 @@ func RunCreate(co *CreateOptions) error {
string(bc),
co.BootstrapFlags.Cleanup)

return d.Create(c, m, pd, co.KubeconfigOutput, pcsFactory)
return d.Create(c, m, md, pd, co.KubeconfigOutput, pcsFactory)
}

func init() {
Expand Down
7 changes: 6 additions & 1 deletion cmd/clusterctl/phases/applymachines.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import (
clusterv1 "sigs.k8s.io/cluster-api/pkg/apis/cluster/v1alpha1"
)

func ApplyMachines(client clusterclient.Client, namespace string, machines []*clusterv1.Machine) error {
func ApplyMachines(client clusterclient.Client, namespace string, machines []*clusterv1.Machine, machineDeployments []*clusterv1.MachineDeployment) error {
if namespace == "" {
namespace = client.GetContextNamespace()
}
Expand All @@ -38,5 +38,10 @@ func ApplyMachines(client clusterclient.Client, namespace string, machines []*cl
return err
}

klog.Infof("Creating machinedeployments in namespace %q", namespace)
if err := client.CreateMachineDeployments(machineDeployments, namespace); err != nil {
return err
}

return nil
}
Loading