Skip to content

Commit

Permalink
work agent track availability
Browse files Browse the repository at this point in the history
  • Loading branch information
Ryan Zhang committed Feb 22, 2024
1 parent d040ce0 commit fad0271
Show file tree
Hide file tree
Showing 13 changed files with 1,255 additions and 133 deletions.
7 changes: 7 additions & 0 deletions apis/placement/v1beta1/binding_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,13 @@ const (
// - "False" means not all the resources are created in the target cluster yet.
// - "Unknown" means it is unknown.
ResourceBindingApplied ResourceBindingConditionType = "Applied"

// ResourceBindingAvailable indicates the available condition of the given resources.
// Its condition status can be one of the following:
// - "True" means all the resources are available in the target cluster.
// - "False" means not all the resources are available in the target cluster yet.
// - "Unknown" means it is unknown.
ResourceBindingAvailable ResourceBindingConditionType = "Applied"
)

// ClusterResourceBindingList is a collection of ClusterResourceBinding.
Expand Down
7 changes: 7 additions & 0 deletions apis/placement/v1beta1/clusterresourceplacement_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -675,6 +675,13 @@ const (
// - "Unknown" means we haven't finished the apply yet.
// TODO: use "Applied" instead.
ResourcesAppliedConditionType ResourcePlacementConditionType = "ResourceApplied"

// ResourcesAvailableConditionType indicates whether the selected resources are available on the selected member cluster.
// Its condition status can be one of the following:
// - "True" means all the selected resources are available on the target cluster.
// - "False" means some of them are not available yet.
// - "Unknown" means we haven't finished the apply yet.
ResourcesAvailableConditionType ResourcePlacementConditionType = "Available"
)

// PlacementType identifies the type of placement.
Expand Down
3 changes: 2 additions & 1 deletion apis/placement/v1beta1/work_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ const (

// WorkConditionTypeApplied represents workload in Work is applied successfully on the spoke cluster.
WorkConditionTypeApplied = "Applied"
// WorkConditionTypeAvailable represents workload in Work exists on the spoke cluster.

// WorkConditionTypeAvailable represents workload in Work is available on the spoke cluster.
WorkConditionTypeAvailable = "Available"
)

Expand Down
2 changes: 1 addition & 1 deletion pkg/controllers/work/applied_work_syncer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ func TestCalculateNewAppliedWork(t *testing.T) {
}
}
if tt.hasErr {
assert.Truef(t, err != nil, "Testcase %s: Should get an err.", testName)
assert.Truef(t, err != nil, "Testcase %s: Should get an applyErr.", testName)
}
})
}
Expand Down
381 changes: 296 additions & 85 deletions pkg/controllers/work/apply_controller.go

Large diffs are not rendered by default.

22 changes: 22 additions & 0 deletions pkg/controllers/work/apply_controller_helper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,28 @@ func waitForWorkToApply(workName, workNS string) *fleetv1beta1.Work {
return &resultWork
}

// waitForWorkToAvailable waits for a work to have an available condition to be true
func waitForWorkToBeAvailable(workName, workNS string) *fleetv1beta1.Work {
var resultWork fleetv1beta1.Work
Eventually(func() bool {
err := k8sClient.Get(context.Background(), types.NamespacedName{Name: workName, Namespace: workNS}, &resultWork)
if err != nil {
return false
}
applyCond := meta.FindStatusCondition(resultWork.Status.Conditions, fleetv1beta1.WorkConditionTypeAvailable)
if applyCond == nil || applyCond.Status != metav1.ConditionTrue || applyCond.ObservedGeneration != resultWork.Generation {
return false
}
for _, manifestCondition := range resultWork.Status.ManifestConditions {
if !meta.IsStatusConditionTrue(manifestCondition.Conditions, fleetv1beta1.WorkConditionTypeAvailable) {
return false
}
}
return true
}, timeout, interval).Should(BeTrue())
return &resultWork
}

// waitForWorkToBeHandled waits for a work to have a finalizer
func waitForWorkToBeHandled(workName, workNS string) *fleetv1beta1.Work {
var resultWork fleetv1beta1.Work
Expand Down
114 changes: 110 additions & 4 deletions pkg/controllers/work/apply_controller_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
kruisev1alpha1 "github.com/openkruise/kruise/apis/apps/v1alpha1"
appv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
Expand Down Expand Up @@ -95,10 +96,8 @@ var _ = Describe("Work Controller", func() {
err := k8sClient.Create(context.Background(), work)
Expect(err).ToNot(HaveOccurred())

resultWork := waitForWorkToApply(work.GetName(), work.GetNamespace())
resultWork := waitForWorkToBeAvailable(work.GetName(), work.GetNamespace())
Expect(len(resultWork.Status.ManifestConditions)).Should(Equal(1))
Expect(meta.IsStatusConditionTrue(resultWork.Status.Conditions, fleetv1beta1.WorkConditionTypeApplied)).Should(BeTrue())
Expect(meta.IsStatusConditionTrue(resultWork.Status.ManifestConditions[0].Conditions, fleetv1beta1.WorkConditionTypeApplied)).Should(BeTrue())
expectedResourceID := fleetv1beta1.WorkResourceIdentifier{
Ordinal: 0,
Group: "",
Expand All @@ -109,13 +108,38 @@ var _ = Describe("Work Controller", func() {
Name: cm.Name,
}
Expect(cmp.Diff(resultWork.Status.ManifestConditions[0].Identifier, expectedResourceID)).Should(BeEmpty())
expected := []metav1.Condition{
{
Type: fleetv1beta1.WorkConditionTypeApplied,
Status: metav1.ConditionTrue,
Reason: ManifestAlreadyUpToDateReason,
},
{
Type: fleetv1beta1.WorkConditionTypeAvailable,
Status: metav1.ConditionTrue,
Reason: string(ManifestNotTrackableAction),
},
}
Expect(cmp.Diff(expected, resultWork.Status.ManifestConditions[0].Conditions, ignoreOption)).Should(BeEmpty())
expected = []metav1.Condition{
{
Type: fleetv1beta1.WorkConditionTypeApplied,
Status: metav1.ConditionTrue,
Reason: workAppliedCompleteReason,
},
{
Type: fleetv1beta1.WorkConditionTypeAvailable,
Status: metav1.ConditionTrue,
Reason: workNotTrackableReason,
},
}
Expect(cmp.Diff(expected, resultWork.Status.Conditions, ignoreOption)).Should(BeEmpty())

By("Check applied config map")
var configMap corev1.ConfigMap
Expect(k8sClient.Get(context.Background(), types.NamespacedName{Name: cmName, Namespace: cmNamespace}, &configMap)).Should(Succeed())
Expect(cmp.Diff(configMap.Labels, cm.Labels)).Should(BeEmpty())
Expect(cmp.Diff(configMap.Data, cm.Data)).Should(BeEmpty())

})

It("Should apply the same manifest in two work properly", func() {
Expand Down Expand Up @@ -591,6 +615,88 @@ var _ = Describe("Work Controller", func() {
}
Expect(cmp.Diff(resultWork.Status.ManifestConditions[0].Identifier, expectedResourceID)).Should(BeEmpty())
})
// has to be in e2e as IT doesn't have the controllers
PIt("Should return workConditionTypeAvailable as true when deployment is available", func() {
deploymentName := "deploy-" + utilrand.String(5) // Create a deployment that is good
deployment := &appv1.Deployment{
TypeMeta: metav1.TypeMeta{
Kind: "Deployment",
APIVersion: "apps/v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: deploymentName,
Namespace: defaultNS,
Labels: map[string]string{"app": "busybox"},
},
Spec: appv1.DeploymentSpec{
Replicas: pointer.Int32(1),
Selector: &metav1.LabelSelector{
MatchLabels: map[string]string{"app": "busybox"},
},
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{"app": "busybox"},
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Image: "busybox",
ImagePullPolicy: corev1.PullIfNotPresent,
Name: "busybox",
},
},
},
},
},
}
work = createWorkWithManifest(workNamespace, deployment)
err := k8sClient.Create(context.Background(), work)
Expect(err).ToNot(HaveOccurred())
resultWork := waitForWorkToBeAvailable(work.GetName(), work.GetNamespace())
Expect(len(resultWork.Status.ManifestConditions)).Should(Equal(1))
expectedResourceID := fleetv1beta1.WorkResourceIdentifier{
Ordinal: 0,
Group: "",
Version: "apps/v1",
Kind: "Deployment",
Resource: "deployments",
Namespace: defaultNS,
Name: deploymentName,
}

Expect(cmp.Diff(resultWork.Status.ManifestConditions[0].Identifier, expectedResourceID)).Should(BeEmpty())
expected := []metav1.Condition{
{
Type: fleetv1beta1.WorkConditionTypeApplied,
Status: metav1.ConditionTrue,
Reason: ManifestAlreadyUpToDateReason,
},
{
Type: fleetv1beta1.WorkConditionTypeAvailable,
Status: metav1.ConditionTrue,
Reason: string(ManifestAvailableAction),
},
}
Expect(cmp.Diff(expected, resultWork.Status.ManifestConditions[0].Conditions, ignoreOption)).Should(BeEmpty())
expected = []metav1.Condition{
{
Type: fleetv1beta1.WorkConditionTypeApplied,
Status: metav1.ConditionTrue,
Reason: workAppliedCompleteReason,
},
{
Type: fleetv1beta1.WorkConditionTypeAvailable,
Status: metav1.ConditionTrue,
Reason: workAvailableReason,
},
}
Expect(cmp.Diff(expected, resultWork.Status.Conditions, ignoreOption)).Should(BeEmpty())
By("Check applied config map")
var appliedDeployment appv1.Deployment
Expect(k8sClient.Get(context.Background(), types.NamespacedName{Name: deploymentName, Namespace: defaultNS}, &appliedDeployment)).Should(Succeed())
Expect(cmp.Diff(appliedDeployment.Labels, deployment.Labels)).Should(BeEmpty())
Expect(cmp.Diff(appliedDeployment.Spec, deployment.Spec)).Should(BeEmpty())
})
})

Context("Test multiple work propagation", func() {
Expand Down
Loading

0 comments on commit fad0271

Please sign in to comment.