Skip to content
Merged
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
44 changes: 29 additions & 15 deletions cmd/memberagent/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import (
fleetv1alpha1 "go.goms.io/fleet/apis/v1alpha1"
imcv1alpha1 "go.goms.io/fleet/pkg/controllers/internalmembercluster/v1alpha1"
imcv1beta1 "go.goms.io/fleet/pkg/controllers/internalmembercluster/v1beta1"
"go.goms.io/fleet/pkg/controllers/work"
workv1alpha1controller "go.goms.io/fleet/pkg/controllers/workv1alpha1"
fleetmetrics "go.goms.io/fleet/pkg/metrics"
"go.goms.io/fleet/pkg/utils"
Expand Down Expand Up @@ -270,30 +271,43 @@ func Start(ctx context.Context, hubCfg, memberConfig *rest.Config, hubOpts, memb
return err
}

// TODO replacing the v1alpha1 work controller
// create the work controller, so we can pass it to the internal member cluster reconciler
workController := workv1alpha1controller.NewApplyWorkReconciler(
hubMgr.GetClient(),
spokeDynamicClient,
memberMgr.GetClient(),
restMapper, hubMgr.GetEventRecorderFor("work_controller"), 5, hubOpts.Namespace)

if err = workController.SetupWithManager(hubMgr); err != nil {
klog.ErrorS(err, "unable to create controller", "controller", "Work")
return err
}

if *enableV1Alpha1APIs {
// create the work controller, so we can pass it to the internal member cluster reconciler
workController := workv1alpha1controller.NewApplyWorkReconciler(
hubMgr.GetClient(),
spokeDynamicClient,
memberMgr.GetClient(),
restMapper, hubMgr.GetEventRecorderFor("work_controller"), 5, hubOpts.Namespace)

if err = workController.SetupWithManager(hubMgr); err != nil {
klog.ErrorS(err, "unable to create v1alpha1 controller", "controller", "work")
return err
}

klog.Info("Setting up the internalMemberCluster v1alpha1 controller")
if err = imcv1alpha1.NewReconciler(hubMgr.GetClient(), memberMgr.GetClient(), workController).SetupWithManager(hubMgr); err != nil {
return fmt.Errorf("unable to create controller v1alpha1 hub_member: %w", err)
klog.ErrorS(err, "unable to create v1alpha1 controller", "controller", "internalMemberCluster")
return fmt.Errorf("unable to create internalMemberCluster v1alpha1 controller: %w", err)
}
}

if *enableV1Beta1APIs {
// create the work controller, so we can pass it to the internal member cluster reconciler
workController := work.NewApplyWorkReconciler(
hubMgr.GetClient(),
spokeDynamicClient,
memberMgr.GetClient(),
restMapper, hubMgr.GetEventRecorderFor("work_controller"), 5, hubOpts.Namespace)

if err = workController.SetupWithManager(hubMgr); err != nil {
klog.ErrorS(err, "unable to create v1beta1 controller", "controller", "work")
return err
}

klog.Info("Setting up the internalMemberCluster v1beta1 controller")
if err = imcv1beta1.NewReconciler(hubMgr.GetClient(), memberMgr.GetClient(), workController).SetupWithManager(hubMgr); err != nil {
return fmt.Errorf("unable to create controller v1beta1 hub_member: %w", err)
klog.ErrorS(err, "unable to create v1beta1 controller", "controller", "internalMemberCluster")
return fmt.Errorf("unable to create internalMemberCluster v1beta1 controller: %w", err)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/predicate"

clusterv1beta1 "go.goms.io/fleet/apis/cluster/v1beta1"
"go.goms.io/fleet/pkg/controllers/workv1alpha1"
"go.goms.io/fleet/pkg/controllers/work"
"go.goms.io/fleet/pkg/metrics"
"go.goms.io/fleet/pkg/utils/condition"
)
Expand All @@ -37,7 +37,7 @@ type Reconciler struct {
// the join/leave agent maintains the list of controllers in the member cluster
// so that it can make sure that all the agents on the member cluster have joined/left
// before updating the internal member cluster CR status
workController *workv1alpha1.ApplyWorkReconciler
workController *work.ApplyWorkReconciler

recorder record.EventRecorder
}
Expand All @@ -55,7 +55,7 @@ const (
)

// NewReconciler creates a new reconciler for the internalMemberCluster CR
func NewReconciler(hubClient client.Client, memberClient client.Client, workController *workv1alpha1.ApplyWorkReconciler) *Reconciler {
func NewReconciler(hubClient client.Client, memberClient client.Client, workController *work.ApplyWorkReconciler) *Reconciler {
return &Reconciler{
hubClient: hubClient,
memberClient: memberClient,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import (
ctrl "sigs.k8s.io/controller-runtime"

clusterv1beta1 "go.goms.io/fleet/apis/cluster/v1beta1"
"go.goms.io/fleet/pkg/controllers/workv1alpha1"
"go.goms.io/fleet/pkg/controllers/work"
"go.goms.io/fleet/pkg/utils"
)

Expand Down Expand Up @@ -58,7 +58,7 @@ var _ = Describe("Test Internal Member Cluster Controller", func() {
}

By("create the internalMemberCluster reconciler")
workController := workv1alpha1.NewApplyWorkReconciler(
workController := work.NewApplyWorkReconciler(
k8sClient, nil, k8sClient, nil, nil, 5, memberClusterNamespace)
r = NewReconciler(k8sClient, k8sClient, workController)
err := r.SetupWithManager(mgr)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import (
"sigs.k8s.io/controller-runtime/pkg/envtest"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
"sigs.k8s.io/controller-runtime/pkg/manager"
workv1alpha1 "sigs.k8s.io/work-api/pkg/apis/v1alpha1"

clusterv1beta1 "go.goms.io/fleet/apis/cluster/v1beta1"
placementv1beta1 "go.goms.io/fleet/apis/placement/v1beta1"
Expand Down Expand Up @@ -64,8 +63,6 @@ var _ = BeforeSuite(func() {
Expect(err).NotTo(HaveOccurred())
err = clusterv1beta1.AddToScheme(scheme.Scheme)
Expect(err).NotTo(HaveOccurred())
err = workv1alpha1.AddToScheme(scheme.Scheme)
Expect(err).NotTo(HaveOccurred())

//+kubebuilder:scaffold:scheme
By("construct the k8s client")
Expand Down
7 changes: 6 additions & 1 deletion pkg/controllers/work/applied_work_syncer.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

/*
Copyright (c) Microsoft Corporation.
Licensed under the MIT license.
*/

package work

import (
Expand Down Expand Up @@ -55,7 +60,7 @@ func (r *ApplyWorkReconciler) generateDiff(ctx context.Context, work *fleetv1bet
}
// add every resource in the work's manifest condition that is applied successfully back to the appliedWork status
for _, manifestCond := range work.Status.ManifestConditions {
ac := meta.FindStatusCondition(manifestCond.Conditions, ConditionTypeApplied)
ac := meta.FindStatusCondition(manifestCond.Conditions, fleetv1beta1.WorkConditionTypeApplied)
if ac == nil {
// should not happen
klog.ErrorS(fmt.Errorf("resource is missing applied condition"), "applied condition missing", "resource", manifestCond.Identifier)
Expand Down
5 changes: 5 additions & 0 deletions pkg/controllers/work/applied_work_syncer_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

/*
Copyright (c) Microsoft Corporation.
Licensed under the MIT license.
*/

package work

import (
Expand Down
9 changes: 7 additions & 2 deletions pkg/controllers/work/applied_work_syncer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

/*
Copyright (c) Microsoft Corporation.
Licensed under the MIT license.
*/

package work

import (
Expand Down Expand Up @@ -106,7 +111,7 @@ func TestCalculateNewAppliedWork(t *testing.T) {
Identifier: workIdentifier,
Conditions: []metav1.Condition{
{
Type: ConditionTypeApplied,
Type: fleetv1beta1.WorkConditionTypeApplied,
Status: metav1.ConditionFalse,
},
},
Expand Down Expand Up @@ -316,7 +321,7 @@ func generateWorkObj(identifier *fleetv1beta1.WorkResourceIdentifier) fleetv1bet
Identifier: *identifier,
Conditions: []metav1.Condition{
{
Type: ConditionTypeApplied,
Type: fleetv1beta1.WorkConditionTypeApplied,
Status: metav1.ConditionTrue,
},
},
Expand Down
39 changes: 22 additions & 17 deletions pkg/controllers/work/apply_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

/*
Copyright (c) Microsoft Corporation.
Licensed under the MIT license.
*/

package work

import (
Expand Down Expand Up @@ -213,7 +218,7 @@ func (r *ApplyWorkReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
// garbageCollectAppliedWork deletes the appliedWork and all the manifests associated with it from the cluster.
func (r *ApplyWorkReconciler) garbageCollectAppliedWork(ctx context.Context, work *fleetv1beta1.Work) (ctrl.Result, error) {
deletePolicy := metav1.DeletePropagationBackground
if !controllerutil.ContainsFinalizer(work, workFinalizer) {
if !controllerutil.ContainsFinalizer(work, fleetv1beta1.WorkFinalizer) {
return ctrl.Result{}, nil
}
// delete the appliedWork which will remove all the manifests associated with it
Expand All @@ -231,7 +236,7 @@ func (r *ApplyWorkReconciler) garbageCollectAppliedWork(ctx context.Context, wor
default:
klog.InfoS("successfully deleted the appliedWork", "appliedWork", work.Name)
}
controllerutil.RemoveFinalizer(work, workFinalizer)
controllerutil.RemoveFinalizer(work, fleetv1beta1.WorkFinalizer)
return ctrl.Result{}, r.client.Update(ctx, work, &client.UpdateOptions{})
}

Expand All @@ -240,7 +245,7 @@ func (r *ApplyWorkReconciler) ensureAppliedWork(ctx context.Context, work *fleet
workRef := klog.KObj(work)
appliedWork := &fleetv1beta1.AppliedWork{}
hasFinalizer := false
if controllerutil.ContainsFinalizer(work, workFinalizer) {
if controllerutil.ContainsFinalizer(work, fleetv1beta1.WorkFinalizer) {
hasFinalizer = true
err := r.spokeClient.Get(ctx, types.NamespacedName{Name: work.Name}, appliedWork)
switch {
Expand Down Expand Up @@ -270,7 +275,7 @@ func (r *ApplyWorkReconciler) ensureAppliedWork(ctx context.Context, work *fleet
}
if !hasFinalizer {
klog.InfoS("add the finalizer to the work", "work", workRef)
work.Finalizers = append(work.Finalizers, workFinalizer)
work.Finalizers = append(work.Finalizers, fleetv1beta1.WorkFinalizer)
return appliedWork, r.client.Update(ctx, work, &client.UpdateOptions{})
}
klog.InfoS("recreated the appliedWork resource", "appliedWork", workRef.Name)
Expand Down Expand Up @@ -389,7 +394,7 @@ func (r *ApplyWorkReconciler) applyUnstructured(ctx context.Context, gvr schema.
}

// We only try to update the object if its spec hash value has changed.
if manifestObj.GetAnnotations()[manifestHashAnnotation] != curObj.GetAnnotations()[manifestHashAnnotation] {
if manifestObj.GetAnnotations()[fleetv1beta1.ManifestHashAnnotation] != curObj.GetAnnotations()[fleetv1beta1.ManifestHashAnnotation] {
// we need to merge the owner reference between the current and the manifest since we support one manifest
// belong to multiple work, so it contains the union of all the appliedWork.
manifestObj.SetOwnerReferences(mergeOwnerReference(curObj.GetOwnerReferences(), manifestObj.GetOwnerReferences()))
Expand Down Expand Up @@ -437,8 +442,8 @@ func (r *ApplyWorkReconciler) patchCurrentResource(ctx context.Context, gvr sche
Namespace: manifestObj.GetNamespace(),
}
klog.V(2).InfoS("manifest is modified", "gvr", gvr, "manifest", manifestRef,
"new hash", manifestObj.GetAnnotations()[manifestHashAnnotation],
"existing hash", curObj.GetAnnotations()[manifestHashAnnotation])
"new hash", manifestObj.GetAnnotations()[fleetv1beta1.ManifestHashAnnotation],
"existing hash", curObj.GetAnnotations()[fleetv1beta1.ManifestHashAnnotation])
// create the three-way merge patch between the current, original and manifest similar to how kubectl apply does
patch, err := threeWayMergePatch(curObj, manifestObj)
if err != nil {
Expand Down Expand Up @@ -516,8 +521,8 @@ func (r *ApplyWorkReconciler) Leave(ctx context.Context) error {
// we leave the resources on the member cluster for now
for _, work := range works.Items {
staleWork := work.DeepCopy()
if controllerutil.ContainsFinalizer(staleWork, workFinalizer) {
controllerutil.RemoveFinalizer(staleWork, workFinalizer)
if controllerutil.ContainsFinalizer(staleWork, fleetv1beta1.WorkFinalizer) {
controllerutil.RemoveFinalizer(staleWork, fleetv1beta1.WorkFinalizer)
if updateErr := r.client.Update(ctx, staleWork, &client.UpdateOptions{}); updateErr != nil {
klog.ErrorS(updateErr, "failed to remove the work finalizer from the work",
"clusterNS", r.workNameSpace, "work", klog.KObj(staleWork))
Expand Down Expand Up @@ -547,8 +552,8 @@ func computeManifestHash(obj *unstructured.Unstructured) (string, error) {
// remove the last applied Annotation to avoid unlimited recursion
annotation := manifest.GetAnnotations()
if annotation != nil {
delete(annotation, manifestHashAnnotation)
delete(annotation, lastAppliedConfigAnnotation)
delete(annotation, fleetv1beta1.ManifestHashAnnotation)
delete(annotation, fleetv1beta1.LastAppliedConfigAnnotation)
if len(annotation) == 0 {
manifest.SetAnnotations(nil)
} else {
Expand Down Expand Up @@ -620,7 +625,7 @@ func setManifestHashAnnotation(manifestObj *unstructured.Unstructured) error {
if annotation == nil {
annotation = map[string]string{}
}
annotation[manifestHashAnnotation] = manifestHash
annotation[fleetv1beta1.ManifestHashAnnotation] = manifestHash
manifestObj.SetAnnotations(annotation)
return nil
}
Expand All @@ -641,7 +646,7 @@ func buildResourceIdentifier(index int, object *unstructured.Unstructured, gvr s
func buildManifestAppliedCondition(err error, action applyAction, observedGeneration int64) metav1.Condition {
if err != nil {
return metav1.Condition{
Type: ConditionTypeApplied,
Type: fleetv1beta1.WorkConditionTypeApplied,
Status: metav1.ConditionFalse,
ObservedGeneration: observedGeneration,
LastTransitionTime: metav1.Now(),
Expand All @@ -651,7 +656,7 @@ func buildManifestAppliedCondition(err error, action applyAction, observedGenera
}

return metav1.Condition{
Type: ConditionTypeApplied,
Type: fleetv1beta1.WorkConditionTypeApplied,
Status: metav1.ConditionTrue,
LastTransitionTime: metav1.Now(),
ObservedGeneration: observedGeneration,
Expand All @@ -664,9 +669,9 @@ func buildManifestAppliedCondition(err error, action applyAction, observedGenera
// If one of the manifests is applied failed on the spoke, the applied status condition of the work is false.
func generateWorkAppliedCondition(manifestConditions []fleetv1beta1.ManifestCondition, observedGeneration int64) metav1.Condition {
for _, manifestCond := range manifestConditions {
if meta.IsStatusConditionFalse(manifestCond.Conditions, ConditionTypeApplied) {
if meta.IsStatusConditionFalse(manifestCond.Conditions, fleetv1beta1.WorkConditionTypeApplied) {
return metav1.Condition{
Type: ConditionTypeApplied,
Type: fleetv1beta1.WorkConditionTypeApplied,
Status: metav1.ConditionFalse,
LastTransitionTime: metav1.Now(),
Reason: "appliedWorkFailed",
Expand All @@ -677,7 +682,7 @@ func generateWorkAppliedCondition(manifestConditions []fleetv1beta1.ManifestCond
}

return metav1.Condition{
Type: ConditionTypeApplied,
Type: fleetv1beta1.WorkConditionTypeApplied,
Status: metav1.ConditionTrue,
LastTransitionTime: metav1.Now(),
Reason: "appliedWorkComplete",
Expand Down
15 changes: 10 additions & 5 deletions pkg/controllers/work/apply_controller_helper_test.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/*
Copyright (c) Microsoft Corporation.
Licensed under the MIT license.
*/

package work

import (
Expand Down Expand Up @@ -51,8 +56,8 @@ func verifyAppliedConfigMap(cm *corev1.ConfigMap) *corev1.ConfigMap {
for key := range cm.Annotations {
Expect(appliedCM.Annotations[key]).Should(Equal(cm.Annotations[key]))
}
Expect(appliedCM.Annotations[manifestHashAnnotation]).ShouldNot(BeEmpty())
Expect(appliedCM.Annotations[lastAppliedConfigAnnotation]).ShouldNot(BeEmpty())
Expect(appliedCM.Annotations[fleetv1beta1.ManifestHashAnnotation]).ShouldNot(BeEmpty())
Expect(appliedCM.Annotations[fleetv1beta1.LastAppliedConfigAnnotation]).ShouldNot(BeEmpty())

By("Check the config map data")
Expect(cmp.Diff(appliedCM.Data, cm.Data)).Should(BeEmpty())
Expand All @@ -67,12 +72,12 @@ func waitForWorkToApply(workName, workNS string) *fleetv1beta1.Work {
if err != nil {
return false
}
applyCond := meta.FindStatusCondition(resultWork.Status.Conditions, ConditionTypeApplied)
applyCond := meta.FindStatusCondition(resultWork.Status.Conditions, fleetv1beta1.WorkConditionTypeApplied)
if applyCond == nil || applyCond.Status != metav1.ConditionTrue || applyCond.ObservedGeneration != resultWork.Generation {
return false
}
for _, manifestCondition := range resultWork.Status.ManifestConditions {
if !meta.IsStatusConditionTrue(manifestCondition.Conditions, ConditionTypeApplied) {
if !meta.IsStatusConditionTrue(manifestCondition.Conditions, fleetv1beta1.WorkConditionTypeApplied) {
return false
}
}
Expand All @@ -89,7 +94,7 @@ func waitForWorkToBeHandled(workName, workNS string) *fleetv1beta1.Work {
if err != nil {
return false
}
return controllerutil.ContainsFinalizer(&resultWork, workFinalizer)
return controllerutil.ContainsFinalizer(&resultWork, fleetv1beta1.WorkFinalizer)
}, timeout, interval).Should(BeTrue())
return &resultWork
}
Loading