forked from kubernetes-sigs/cluster-api
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request kubernetes-sigs#29 from abhinavmpandey08/in-place-md
✨ Add support for in-place upgrades in MachineDeployments
- Loading branch information
Showing
8 changed files
with
173 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
44 changes: 44 additions & 0 deletions
44
internal/controllers/machinedeployment/machinedeployment_inplace.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package machinedeployment | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/pkg/errors" | ||
kerrors "k8s.io/apimachinery/pkg/util/errors" | ||
ctrl "sigs.k8s.io/controller-runtime" | ||
|
||
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" | ||
"sigs.k8s.io/cluster-api/util/annotations" | ||
) | ||
|
||
func (r *Reconciler) rolloutInPlace(ctx context.Context, md *clusterv1.MachineDeployment, msList []*clusterv1.MachineSet) (reterr error) { | ||
log := ctrl.LoggerFrom(ctx) | ||
|
||
// For in-place upgrade, we shouldn't try to create a new MachineSet as that would trigger a rollout. | ||
// Instead, we should try to get latest MachineSet that matches the MachineDeployment.Spec.Template/ | ||
// If no such MachineSet exists yet, this means the MachineSet hasn't been in-place upgraded yet. | ||
// The external in-place upgrade implementer is responsible for updating the latest MachineSet's template | ||
// after in-place upgrade of all worker nodes belonging to the MD is complete. | ||
// Once the MachineSet is updated, this function will return the latest MachineSet that matches the | ||
// MachineDeployment template and thus we can deduce that the in-place upgrade is complete. | ||
newMachineSet, oldMachineSets, err := r.getAllMachineSetsAndSyncRevision(ctx, md, msList, false) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
defer func() { | ||
allMSs := append(oldMachineSets, newMachineSet) | ||
|
||
// Always attempt to sync the status | ||
err := r.syncDeploymentStatus(allMSs, newMachineSet, md) | ||
reterr = kerrors.NewAggregate([]error{reterr, err}) | ||
}() | ||
|
||
if newMachineSet == nil { | ||
log.Info("Changes detected, InPlace upgrade strategy detected, adding the annotation") | ||
annotations.AddAnnotations(md, map[string]string{clusterv1.MachineDeploymentInPlaceUpgradeAnnotation: "true"}) | ||
return errors.New("new MachineSet not found. This most likely means that the in-place upgrade hasn't finished yet") | ||
} | ||
|
||
return r.sync(ctx, md, msList) | ||
} |
110 changes: 110 additions & 0 deletions
110
internal/controllers/machinedeployment/machinedeployment_inplace_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
package machinedeployment | ||
|
||
import ( | ||
"testing" | ||
|
||
. "github.com/onsi/gomega" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/client-go/tools/record" | ||
"k8s.io/utils/pointer" | ||
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" | ||
"sigs.k8s.io/controller-runtime/pkg/client" | ||
"sigs.k8s.io/controller-runtime/pkg/client/fake" | ||
) | ||
|
||
const ( | ||
mdName = "my-md" | ||
msName = "my-ms" | ||
version128 = "v1.28.0" | ||
version129 = "v1.29.0" | ||
) | ||
|
||
func getMachineDeployment(name string, version string, replicas int32) *clusterv1.MachineDeployment { | ||
return &clusterv1.MachineDeployment{ | ||
ObjectMeta: metav1.ObjectMeta{ | ||
Name: name, | ||
}, | ||
Spec: clusterv1.MachineDeploymentSpec{ | ||
Strategy: &clusterv1.MachineDeploymentStrategy{ | ||
Type: clusterv1.InPlaceMachineDeploymentStrategyType, | ||
}, | ||
Replicas: pointer.Int32(replicas), | ||
Template: clusterv1.MachineTemplateSpec{ | ||
Spec: clusterv1.MachineSpec{ | ||
ClusterName: "my-cluster", | ||
Version: pointer.String(version), | ||
}, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func getMachineSet(name string, version string, replicas int32) *clusterv1.MachineSet { | ||
return &clusterv1.MachineSet{ | ||
ObjectMeta: metav1.ObjectMeta{ | ||
Name: name, | ||
}, | ||
Spec: clusterv1.MachineSetSpec{ | ||
Replicas: pointer.Int32(replicas), | ||
Template: clusterv1.MachineTemplateSpec{ | ||
Spec: clusterv1.MachineSpec{ | ||
ClusterName: "my-cluster", | ||
Version: pointer.String(version), | ||
}, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func TestRolloutInPlace(t *testing.T) { | ||
testCases := []struct { | ||
name string | ||
machineDeployment *clusterv1.MachineDeployment | ||
msList []*clusterv1.MachineSet | ||
annotationExpected bool | ||
expectErr bool | ||
}{ | ||
{ | ||
name: "MD template matches MS template", | ||
machineDeployment: getMachineDeployment(mdName, version128, 2), | ||
msList: []*clusterv1.MachineSet{getMachineSet(msName, version128, 2)}, | ||
annotationExpected: false, | ||
expectErr: false, | ||
}, | ||
{ | ||
name: "MD template doesn't MS template", | ||
machineDeployment: getMachineDeployment(mdName, version128, 2), | ||
msList: []*clusterv1.MachineSet{getMachineSet(msName, version129, 2)}, | ||
annotationExpected: true, | ||
expectErr: true, | ||
}, | ||
} | ||
|
||
for _, tc := range testCases { | ||
t.Run(tc.name, func(t *testing.T) { | ||
g := NewWithT(t) | ||
|
||
resources := []client.Object{ | ||
tc.machineDeployment, | ||
} | ||
|
||
for key := range tc.msList { | ||
resources = append(resources, tc.msList[key]) | ||
} | ||
|
||
r := &Reconciler{ | ||
Client: fake.NewClientBuilder().WithObjects(resources...).Build(), | ||
recorder: record.NewFakeRecorder(32), | ||
} | ||
|
||
err := r.rolloutInPlace(ctx, tc.machineDeployment, tc.msList) | ||
if tc.expectErr { | ||
g.Expect(err).To(HaveOccurred()) | ||
} | ||
|
||
_, ok := tc.machineDeployment.Annotations[clusterv1.MachineDeploymentInPlaceUpgradeAnnotation] | ||
g.Expect(ok).To(Equal(tc.annotationExpected)) | ||
}) | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters