Skip to content

Commit fa63630

Browse files
authored
Allow disabling version availability check at the start of the upgrade (#177)
Adds a new field `.spec.desiredVersionCheckAvailability`, defaulting to true, to the `UpgradeJob` definition.
1 parent aad31f5 commit fa63630

5 files changed

Lines changed: 92 additions & 2 deletions

File tree

api/v1beta1/upgradejob_types.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,26 @@ type UpgradeJobSpec struct {
7272
// +optional
7373
DesiredVersion *configv1.Update `json:"desiredVersion,omitempty"`
7474

75+
// DesiredVersionCheckAvailability defines whether to check if the desired version is available at the start of the upgrade.
76+
// This is done by searching the ClusterVersion status for the desired version.
77+
// If set to true, the upgrade job will fail with reason UpgradeJobReasonUpgradeWithdrawn if the desired version is not available.
78+
// If set to false, the upgrade job will not check for the availability of the desired version and will apply the DesiredVersion directly.
79+
// Defaults to true.
80+
// +optional
81+
DesiredVersionCheckAvailability *bool `json:"desiredVersionCheckAvailability,omitempty"`
82+
7583
// UpgradeJobConfig defines the configuration for the upgrade job
7684
UpgradeJobConfig `json:"config"`
7785
}
7886

87+
// GetDesiredVersionCheckAvailability returns DesiredVersionCheckAvailability with a default value of true if nil.
88+
func (s UpgradeJobSpec) GetDesiredVersionCheckAvailability() bool {
89+
if s.DesiredVersionCheckAvailability == nil {
90+
return true
91+
}
92+
return *s.DesiredVersionCheckAvailability
93+
}
94+
7995
// UpgradeJobConfig defines the configuration for the upgrade job
8096
type UpgradeJobConfig struct {
8197
// UpgradeTimeout defines the timeout after which the upgrade is considered failed.

api/v1beta1/zz_generated.deepcopy.go

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/crd/bases/managedupgrade.appuio.io_upgradejobs.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,14 @@ spec:
214214
- message: Version must be set if Architecture is set
215215
rule: 'has(self.architecture) && self.architecture != '''' ? self.version
216216
!= '''' : true'
217+
desiredVersionCheckAvailability:
218+
description: |-
219+
DesiredVersionCheckAvailability defines whether to check if the desired version is available at the start of the upgrade.
220+
This is done by searching the ClusterVersion status for the desired version.
221+
If set to true, the upgrade job will fail with reason UpgradeJobReasonUpgradeWithdrawn if the desired version is not available.
222+
If set to false, the upgrade job will not check for the availability of the desired version and will apply the DesiredVersion directly.
223+
Defaults to true.
224+
type: boolean
217225
startAfter:
218226
description: StartAfter defines the time after which the upgrade job
219227
should start

controllers/upgradejob_controller.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -226,8 +226,8 @@ func (r *UpgradeJobReconciler) reconcileStartedJob(ctx context.Context, uj *mana
226226
if uj.Spec.DesiredVersion != nil {
227227
// Check if the desired version is already set
228228
if version.Spec.DesiredUpdate == nil || *version.Spec.DesiredUpdate != *uj.Spec.DesiredVersion {
229-
update := clusterversion.FindAvailableUpdate(version, uj.Spec.DesiredVersion.Image, uj.Spec.DesiredVersion.Version)
230-
if update == nil {
229+
if uj.Spec.GetDesiredVersionCheckAvailability() &&
230+
clusterversion.FindAvailableUpdate(version, uj.Spec.DesiredVersion.Image, uj.Spec.DesiredVersion.Version) == nil {
231231
r.setStatusCondition(&uj.Status.Conditions, metav1.Condition{
232232
Type: managedupgradev1beta1.UpgradeJobConditionFailed,
233233
Status: metav1.ConditionTrue,

controllers/upgradejob_controller_test.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"k8s.io/apimachinery/pkg/runtime"
2020
"k8s.io/apimachinery/pkg/types"
2121
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
22+
"k8s.io/utils/ptr"
2223
ctrl "sigs.k8s.io/controller-runtime"
2324
"sigs.k8s.io/controller-runtime/pkg/client"
2425
"sigs.k8s.io/controller-runtime/pkg/client/fake"
@@ -977,6 +978,66 @@ func Test_UpgradeJobReconciler_Reconcile_UpgradeWithdrawn(t *testing.T) {
977978
require.Empty(t, ucv.Annotations[JobLockAnnotation], "should clear lock annotation")
978979
}
979980

981+
func Test_UpgradeJobReconciler_Reconcile_UpgradeWithdrawn_NoCheckAvailability(t *testing.T) {
982+
ctx := log.IntoContext(t.Context(), testr.New(t))
983+
clock := mockClock{now: time.Date(2022, 12, 4, 22, 45, 0, 0, time.UTC)}
984+
985+
ucv := &configv1.ClusterVersion{
986+
ObjectMeta: metav1.ObjectMeta{
987+
Name: "version",
988+
},
989+
Spec: configv1.ClusterVersionSpec{
990+
ClusterID: "9b588658-9671-429c-a762-34106da5795f",
991+
DesiredUpdate: &configv1.Update{
992+
Version: "4.5.12",
993+
Image: "quay.io/openshift-release-dev/ocp-release@sha256:d732fee6462de7f04f9432f1bb3925f57554db1d8c8d6f3138eea70e5787c7ae",
994+
},
995+
},
996+
Status: configv1.ClusterVersionStatus{},
997+
}
998+
999+
upgradeJob := &managedupgradev1beta1.UpgradeJob{
1000+
ObjectMeta: metav1.ObjectMeta{
1001+
Name: "upgrade-1234-4-5-13",
1002+
Namespace: "appuio-openshift-upgrade-controller",
1003+
},
1004+
Spec: managedupgradev1beta1.UpgradeJobSpec{
1005+
StartBefore: metav1.NewTime(clock.Now().Add(time.Hour)),
1006+
StartAfter: metav1.NewTime(clock.Now().Add(-time.Hour)),
1007+
DesiredVersionCheckAvailability: ptr.To(false),
1008+
DesiredVersion: &configv1.Update{
1009+
Version: "4.5.13",
1010+
Image: "quay.io/openshift-release-dev/ocp-release@sha256:d094f1952995b3c5fd8e0b19b128905931e1e8fdb4b6cb377857ab0dfddcff47",
1011+
},
1012+
UpgradeJobConfig: managedupgradev1beta1.UpgradeJobConfig{
1013+
UpgradeTimeout: metav1.Duration{Duration: 12 * time.Hour},
1014+
PreUpgradeHealthChecks: managedupgradev1beta1.UpgradeJobHealthCheck{
1015+
SkipDegradedOperatorsCheck: true,
1016+
},
1017+
},
1018+
},
1019+
}
1020+
1021+
client := controllerClient(t, ucv, upgradeJob)
1022+
1023+
subject := &UpgradeJobReconciler{
1024+
Client: client,
1025+
Scheme: client.Scheme(),
1026+
1027+
Clock: &clock,
1028+
1029+
ManagedUpstreamClusterVersionName: "version",
1030+
}
1031+
1032+
reconcileNTimes(t, subject, ctx, requestForObject(upgradeJob), 10)
1033+
1034+
require.NoError(t, client.Get(ctx, requestForObject(upgradeJob).NamespacedName, upgradeJob))
1035+
failedCond := apimeta.FindStatusCondition(upgradeJob.Status.Conditions, managedupgradev1beta1.UpgradeJobConditionFailed)
1036+
require.Nil(t, failedCond, "should not fail")
1037+
require.NoError(t, client.Get(ctx, requestForObject(ucv).NamespacedName, ucv))
1038+
require.Equal(t, upgradeJob.Spec.DesiredVersion.Version, ucv.Spec.DesiredUpdate.Version, "should update cluster version")
1039+
}
1040+
9801041
func Test_UpgradeJobReconciler_Reconcile_Timeout(t *testing.T) {
9811042
ctx := log.IntoContext(t.Context(), testr.New(t))
9821043
clock := mockClock{now: time.Date(2022, 12, 4, 22, 45, 0, 0, time.UTC)}

0 commit comments

Comments
 (0)