Skip to content

Commit 209c7d7

Browse files
Merge pull request #81 from CrystalChun/update-cvo
MGMT-19877: Trigger workload cluster upgrade
2 parents 8f7fde0 + 850f694 commit 209c7d7

File tree

3 files changed

+115
-2
lines changed

3 files changed

+115
-2
lines changed

Diff for: controlplane/internal/controller/openshiftassistedcontrolplane_controller.go

+5-2
Original file line numberDiff line numberDiff line change
@@ -190,8 +190,11 @@ func (r *OpenshiftAssistedControlPlaneReconciler) Reconcile(ctx context.Context,
190190
}
191191

192192
if upgrade.IsUpgradeRequested(ctx, oacp) {
193-
//TODO: Handle upgrade request
194-
log.Info("upgrade for control plane has been requested")
193+
log.Info("workload cluster upgrade has been requested, starting upgrade", "current workload cluster version", oacp.Status.DistributionVersion, "new workload cluster version", oacp.Spec.DistributionVersion)
194+
if err := upgrade.UpgradeWorkloadCluster(ctx, r.Client, r.WorkloadClusterClientGenerator, oacp); err != nil {
195+
log.Error(err, "failed to upgrade workload cluster")
196+
}
197+
log.Info("workload cluster upgrade set on ClusterVersion, waiting completion")
195198
}
196199
return ctrl.Result{}, r.reconcileReplicas(ctx, oacp, cluster)
197200
}

Diff for: controlplane/internal/upgrade/upgrade.go

+38
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@ import (
2020
"sigs.k8s.io/controller-runtime/pkg/client"
2121
)
2222

23+
const (
24+
// UpgradeImageOverrideAnnotation is a (temporary) solution to provide an upgrade image to CVO
25+
// It is used while the OCP version being used for testing is not GA and should not be necessary if
26+
// a GA version of OCP is used.
27+
// Example: GA version = 4.19.0, Non-GA = 4.19.0-0.nightly-2025-01-30-091858
28+
UpgradeImageOverrideAnnotation = "cluster.x-k8s.io/upgrade-image-override"
29+
)
30+
2331
func IsUpgradeRequested(ctx context.Context, oacp *controlplanev1alpha2.OpenshiftAssistedControlPlane) bool {
2432
log := ctrl.LoggerFrom(ctx)
2533
oacpDistVersion, err := semver.NewVersion(oacp.Spec.DistributionVersion)
@@ -103,3 +111,33 @@ func isKubeconfigAvailable(oacp *controlplanev1alpha2.OpenshiftAssistedControlPl
103111
}
104112
return kubeconfigFoundCondition.Status == corev1.ConditionTrue
105113
}
114+
115+
func UpgradeWorkloadCluster(ctx context.Context, client client.Client,
116+
workloadClusterClientGenerator workloadclient.ClientGenerator,
117+
oacp *controlplanev1alpha2.OpenshiftAssistedControlPlane) error {
118+
workloadClient, err := getWorkloadClient(ctx, client, workloadClusterClientGenerator, oacp)
119+
if err != nil {
120+
return err
121+
}
122+
123+
if workloadClient == nil {
124+
return fmt.Errorf("workload client is not available yet")
125+
}
126+
127+
var clusterVersion configv1.ClusterVersion
128+
if err := workloadClient.Get(ctx, types.NamespacedName{Name: "version"}, &clusterVersion); err != nil {
129+
err = errors.Join(err, fmt.Errorf(("failed to get ClusterVersion from workload cluster")))
130+
return err
131+
}
132+
133+
clusterVersion.Spec.DesiredUpdate = &configv1.Update{
134+
Version: oacp.Spec.DistributionVersion,
135+
}
136+
137+
if releaseImage, ok := oacp.Annotations[UpgradeImageOverrideAnnotation]; ok {
138+
clusterVersion.Spec.DesiredUpdate.Image = releaseImage
139+
clusterVersion.Spec.DesiredUpdate.Force = true
140+
}
141+
142+
return workloadClient.Update(ctx, &clusterVersion)
143+
}

Diff for: controlplane/internal/upgrade/upgrade_test.go

+72
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,78 @@ var _ = Describe("Upgrade", func() {
160160
})
161161
})
162162
})
163+
Context("Upgrading", func() {
164+
const (
165+
openshiftAssistedControlPlaneName = "test-resource"
166+
clusterName = "test-cluster"
167+
namespace = "test"
168+
)
169+
var (
170+
ctx = context.Background()
171+
cluster *clusterv1.Cluster
172+
mockCtrl *gomock.Controller
173+
k8sClient client.Client
174+
mockWorkloadClientGenerator *mockWorkloadClient
175+
)
176+
BeforeEach(func() {
177+
k8sClient = fakeclient.NewClientBuilder().
178+
WithScheme(testScheme).
179+
WithStatusSubresource(&controlplanev1alpha2.OpenshiftAssistedControlPlane{}).Build()
180+
181+
mockCtrl = gomock.NewController(GinkgoT())
182+
ns := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: namespace}}
183+
Expect(k8sClient.Create(ctx, ns)).To(Succeed())
184+
185+
mockWorkloadClientGenerator = NewMockWorkloadClient()
186+
187+
By("creating a cluster")
188+
cluster = &clusterv1.Cluster{}
189+
err := k8sClient.Get(ctx, types.NamespacedName{Name: clusterName, Namespace: namespace}, cluster)
190+
if err != nil && errors.IsNotFound(err) {
191+
cluster = testutils.NewCluster(clusterName, namespace)
192+
err := k8sClient.Create(ctx, cluster)
193+
Expect(err).NotTo(HaveOccurred())
194+
}
195+
})
196+
197+
AfterEach(func() {
198+
mockCtrl.Finish()
199+
k8sClient = nil
200+
})
201+
When("Upgrade is requested", func() {
202+
It("should update the workload cluster's cluster version to have the correct desired update", func() {
203+
By("creating the openshift assisted control plane")
204+
openshiftAssistedControlPlane := testutils.NewOpenshiftAssistedControlPlane(namespace, openshiftAssistedControlPlaneName)
205+
openshiftAssistedControlPlane.Status.DistributionVersion = "4.12.0"
206+
openshiftAssistedControlPlane.Labels = map[string]string{
207+
clusterv1.ClusterNameLabel: cluster.Name,
208+
}
209+
conditions.MarkTrue(openshiftAssistedControlPlane, controlplanev1alpha2.KubeconfigAvailableCondition)
210+
By("creating the kubeconfig secret")
211+
kubeconfigSecret := &corev1.Secret{
212+
ObjectMeta: metav1.ObjectMeta{
213+
Name: fmt.Sprintf("%s-kubeconfig", cluster.Name),
214+
Namespace: openshiftAssistedControlPlane.Namespace,
215+
},
216+
Data: map[string][]byte{
217+
"value": []byte("kubeconfig"),
218+
},
219+
}
220+
Expect(k8sClient.Create(ctx, kubeconfigSecret)).To(Succeed())
221+
By("creating a cluster version using the workload cluster's client")
222+
mockWorkloadClientGenerator.MockCreateClusterVersion("4.12.0")
223+
224+
By("calling UpgradeWorkloadCluster")
225+
Expect(UpgradeWorkloadCluster(ctx, k8sClient, mockWorkloadClientGenerator, openshiftAssistedControlPlane)).To(Succeed())
226+
227+
By("checking the workload cluster's cluster version for the desired update field")
228+
workloadClusterVersion := &configv1.ClusterVersion{}
229+
Expect(mockWorkloadClientGenerator.mockClient.Get(ctx, types.NamespacedName{Name: "version"}, workloadClusterVersion)).To(Succeed())
230+
Expect(workloadClusterVersion.Spec.DesiredUpdate).NotTo(BeNil())
231+
Expect(workloadClusterVersion.Spec.DesiredUpdate.Version).To(Equal(openshiftAssistedControlPlane.Spec.DistributionVersion))
232+
})
233+
})
234+
})
163235
})
164236

165237
type mockWorkloadClient struct {

0 commit comments

Comments
 (0)