Handle hosted mode addons in addon progressing controller (#464)

Signed-off-by: zhujian <jiazhu@redhat.com>
This commit is contained in:
Jian Zhu
2024-05-16 01:56:57 +00:00
committed by GitHub
parent 319d9af8a1
commit df3b290dc5
6 changed files with 800 additions and 19 deletions
@@ -38,7 +38,7 @@ const (
ProgressingFailed string = "Failed"
)
// addonProgressingController reconciles instances of managedclusteradd on the hub
// addonProgressingController reconciles instances of managedclusteraddon on the hub
// based to update the status progressing condition and last applied config
type addonProgressingController struct {
addonClient addonv1alpha1client.Interface
@@ -67,11 +67,18 @@ func NewAddonProgressingController(
return factory.New().WithInformersQueueKeysFunc(
queue.QueueKeyByMetaNamespaceName,
addonInformers.Informer(), clusterManagementAddonInformers.Informer()).
// TODO: consider hosted manifestwork
WithInformersQueueKeysFunc(
WithFilteredEventsInformersQueueKeysFunc(
func(obj runtime.Object) []string {
accessor, _ := meta.Accessor(obj)
return []string{fmt.Sprintf("%s/%s", accessor.GetNamespace(), accessor.GetLabels()[addonapiv1alpha1.AddonLabelKey])}
namespace := accessor.GetNamespace()
if len(accessor.GetLabels()[addonapiv1alpha1.AddonNamespaceLabelKey]) > 0 {
namespace = accessor.GetLabels()[addonapiv1alpha1.AddonNamespaceLabelKey]
}
return []string{fmt.Sprintf("%s/%s", namespace, accessor.GetLabels()[addonapiv1alpha1.AddonLabelKey])}
},
func(obj interface{}) bool {
accessor, _ := meta.Accessor(obj)
return len(accessor.GetLabels()) > 0 && len(accessor.GetLabels()[addonapiv1alpha1.AddonLabelKey]) > 0
},
workInformers.Informer()).
WithSync(c.sync).ToController("addon-progressing-controller", recorder)
@@ -117,22 +124,26 @@ func (c *addonProgressingController) sync(ctx context.Context, syncCtx factory.S
func (c *addonProgressingController) updateAddonProgressingAndLastApplied(
ctx context.Context, newaddon, oldaddon *addonapiv1alpha1.ManagedClusterAddOn) (bool, error) {
patcher := patcher.NewPatcher[
*addonapiv1alpha1.ManagedClusterAddOn, addonapiv1alpha1.ManagedClusterAddOnSpec, addonapiv1alpha1.ManagedClusterAddOnStatus](
*addonapiv1alpha1.ManagedClusterAddOn,
addonapiv1alpha1.ManagedClusterAddOnSpec,
addonapiv1alpha1.ManagedClusterAddOnStatus](
c.addonClient.AddonV1alpha1().ManagedClusterAddOns(newaddon.Namespace))
// check config references
if supported, config := isConfigurationSupported(newaddon); !supported {
meta.SetStatusCondition(&newaddon.Status.Conditions, metav1.Condition{
Type: addonapiv1alpha1.ManagedClusterAddOnConditionProgressing,
Status: metav1.ConditionFalse,
Reason: addonapiv1alpha1.ProgressingReasonConfigurationUnsupported,
Message: fmt.Sprintf("Configuration with gvr %s/%s is not supported for this addon", config.Group, config.Resource),
Type: addonapiv1alpha1.ManagedClusterAddOnConditionProgressing,
Status: metav1.ConditionFalse,
Reason: addonapiv1alpha1.ProgressingReasonConfigurationUnsupported,
Message: fmt.Sprintf("Configuration with gvr %s/%s is not supported for this addon",
config.Group, config.Resource),
})
return patcher.PatchStatus(ctx, newaddon, newaddon.Status, oldaddon.Status)
}
// wait until addon has ManifestApplied condition
if cond := meta.FindStatusCondition(newaddon.Status.Conditions, addonapiv1alpha1.ManagedClusterAddOnManifestApplied); cond == nil {
if cond := meta.FindStatusCondition(
newaddon.Status.Conditions, addonapiv1alpha1.ManagedClusterAddOnManifestApplied); cond == nil {
meta.SetStatusCondition(&newaddon.Status.Conditions, metav1.Condition{
Type: addonapiv1alpha1.ManagedClusterAddOnConditionProgressing,
Status: metav1.ConditionFalse,
@@ -142,6 +153,25 @@ func (c *addonProgressingController) updateAddonProgressingAndLastApplied(
return patcher.PatchStatus(ctx, newaddon, newaddon.Status, oldaddon.Status)
}
var hostingClusterName string = ""
if newaddon.Annotations != nil && len(newaddon.Annotations[addonapiv1alpha1.HostingClusterNameAnnotationKey]) > 0 {
hostingClusterName = newaddon.Annotations[addonapiv1alpha1.HostingClusterNameAnnotationKey]
}
if len(hostingClusterName) > 0 {
// wait until addon has HostingManifestApplied condition
if cond := meta.FindStatusCondition(
newaddon.Status.Conditions, addonapiv1alpha1.ManagedClusterAddOnHostingManifestApplied); cond == nil {
meta.SetStatusCondition(&newaddon.Status.Conditions, metav1.Condition{
Type: addonapiv1alpha1.ManagedClusterAddOnConditionProgressing,
Status: metav1.ConditionFalse,
Reason: "WaitingForHostingManifestApplied",
Message: "Waiting for ManagedClusterAddOn HostingManifestApplied condition",
})
return patcher.PatchStatus(ctx, newaddon, newaddon.Status, oldaddon.Status)
}
}
// set upgrade flag
isUpgrade := false
for _, configReference := range newaddon.Status.ConfigReferences {
@@ -152,7 +182,6 @@ func (c *addonProgressingController) updateAddonProgressingAndLastApplied(
}
// get addon works
// TODO: consider hosted manifestwork
requirement, _ := labels.NewRequirement(addonapiv1alpha1.AddonLabelKey, selection.Equals, []string{newaddon.Name})
selector := labels.NewSelector().Add(*requirement)
addonWorks, err := c.workLister.ManifestWorks(newaddon.Namespace).List(selector)
@@ -161,6 +190,16 @@ func (c *addonProgressingController) updateAddonProgressingAndLastApplied(
return patcher.PatchStatus(ctx, newaddon, newaddon.Status, oldaddon.Status)
}
if len(hostingClusterName) > 0 {
// get hosted addon works
hostedAddonWorks, err := c.workLister.ManifestWorks(hostingClusterName).List(selector)
if err != nil {
setAddOnProgressingAndLastApplied(isUpgrade, ProgressingFailed, err.Error(), newaddon)
return patcher.PatchStatus(ctx, newaddon, newaddon.Status, oldaddon.Status)
}
addonWorks = append(addonWorks, hostedAddonWorks...)
}
if len(addonWorks) == 0 {
setAddOnProgressingAndLastApplied(isUpgrade, ProgressingDoing, "no addon works", newaddon)
return patcher.PatchStatus(ctx, newaddon, newaddon.Status, oldaddon.Status)
@@ -52,13 +52,29 @@ func TestReconcile(t *testing.T) {
},
{
name: "no work applied condition",
syncKey: "test/test",
syncKey: "cluster1/test",
managedClusteraddon: []runtime.Object{
addontesting.NewAddon("test", "cluster1"),
},
clusterManagementAddon: []runtime.Object{addontesting.NewClusterManagementAddon("test", "testcrd", "testcr").Build()},
work: []runtime.Object{},
validateAddonActions: testingcommon.AssertNoActions,
validateAddonActions: func(t *testing.T, actions []clienttesting.Action) {
testingcommon.AssertActions(t, actions, "patch")
actual := actions[0].(clienttesting.PatchActionImpl).Patch
addOn := &addonapiv1alpha1.ManagedClusterAddOn{}
err := json.Unmarshal(actual, addOn)
if err != nil {
t.Fatal(err)
}
configCond := meta.FindStatusCondition(
addOn.Status.Conditions, addonapiv1alpha1.ManagedClusterAddOnConditionProgressing)
if !(configCond != nil &&
configCond.Reason == "WaitingForManifestApplied" &&
configCond.Status == metav1.ConditionFalse) {
t.Errorf("Condition Progressing is incorrect")
}
},
},
{
name: "update managedclusteraddon to installing when no work",
@@ -612,3 +628,731 @@ func TestReconcile(t *testing.T) {
})
}
}
func TestReconcileHostedAddons(t *testing.T) {
cases := []struct {
name string
syncKey string
managedClusteraddon []runtime.Object
clusterManagementAddon []runtime.Object
work []runtime.Object
validateAddonActions func(t *testing.T, actions []clienttesting.Action)
}{
{
name: "no work applied condition",
syncKey: "cluster1/test",
managedClusteraddon: []runtime.Object{
addontesting.NewHostedModeAddon("test", "cluster1", "hosting-cluster"),
},
clusterManagementAddon: []runtime.Object{
addontesting.NewClusterManagementAddon("test", "testcrd", "testcr").Build(),
},
work: []runtime.Object{},
validateAddonActions: func(t *testing.T, actions []clienttesting.Action) {
testingcommon.AssertActions(t, actions, "patch")
actual := actions[0].(clienttesting.PatchActionImpl).Patch
addOn := &addonapiv1alpha1.ManagedClusterAddOn{}
err := json.Unmarshal(actual, addOn)
if err != nil {
t.Fatal(err)
}
configCond := meta.FindStatusCondition(
addOn.Status.Conditions, addonapiv1alpha1.ManagedClusterAddOnConditionProgressing)
if !(configCond != nil &&
configCond.Reason == "WaitingForManifestApplied" &&
configCond.Status == metav1.ConditionFalse) {
t.Errorf("Condition Progressing is incorrect")
}
},
},
{
name: "no hosting work applied condition",
syncKey: "cluster1/test",
managedClusteraddon: []runtime.Object{
addontesting.NewHostedModeAddon("test", "cluster1", "hosting-cluster",
metav1.Condition{
Type: addonapiv1alpha1.ManagedClusterAddOnManifestApplied,
Status: metav1.ConditionTrue,
Reason: addonapiv1alpha1.AddonManifestAppliedReasonManifestsApplied,
Message: "manifests of addon are applied successfully",
},
),
},
clusterManagementAddon: []runtime.Object{
addontesting.NewClusterManagementAddon("test", "testcrd", "testcr").Build(),
},
work: []runtime.Object{},
validateAddonActions: func(t *testing.T, actions []clienttesting.Action) {
testingcommon.AssertActions(t, actions, "patch")
actual := actions[0].(clienttesting.PatchActionImpl).Patch
addOn := &addonapiv1alpha1.ManagedClusterAddOn{}
err := json.Unmarshal(actual, addOn)
if err != nil {
t.Fatal(err)
}
configCond := meta.FindStatusCondition(
addOn.Status.Conditions, addonapiv1alpha1.ManagedClusterAddOnConditionProgressing)
if !(configCond != nil &&
configCond.Reason == "WaitingForHostingManifestApplied" &&
configCond.Status == metav1.ConditionFalse) {
t.Errorf("Condition Progressing is incorrect")
}
},
},
{
name: "update managedclusteraddon to installing when no work",
syncKey: "cluster1/test",
managedClusteraddon: []runtime.Object{
addontesting.NewHostedModeAddon("test", "cluster1", "hosting-cluster",
metav1.Condition{
Type: addonapiv1alpha1.ManagedClusterAddOnManifestApplied,
Status: metav1.ConditionTrue,
Reason: addonapiv1alpha1.AddonManifestAppliedReasonManifestsApplied,
Message: "manifests of addon are applied successfully",
},
metav1.Condition{
Type: addonapiv1alpha1.ManagedClusterAddOnHostingManifestApplied,
Status: metav1.ConditionTrue,
Reason: addonapiv1alpha1.AddonManifestAppliedReasonManifestsApplied,
Message: "hosting manifests of addon are applied successfully",
},
),
},
clusterManagementAddon: []runtime.Object{
addontesting.NewClusterManagementAddon("test", "testcrd", "testcr").Build(),
},
work: []runtime.Object{},
validateAddonActions: func(t *testing.T, actions []clienttesting.Action) {
testingcommon.AssertActions(t, actions, "patch")
actual := actions[0].(clienttesting.PatchActionImpl).Patch
addOn := &addonapiv1alpha1.ManagedClusterAddOn{}
err := json.Unmarshal(actual, addOn)
if err != nil {
t.Fatal(err)
}
configCond := meta.FindStatusCondition(
addOn.Status.Conditions, addonapiv1alpha1.ManagedClusterAddOnConditionProgressing)
if !(configCond != nil &&
configCond.Reason == addonapiv1alpha1.ProgressingReasonInstalling &&
configCond.Status == metav1.ConditionTrue) {
t.Errorf("Condition Progressing is incorrect")
}
},
},
{
name: "update managedclusteraddon to installing when work config spec not match",
syncKey: "cluster1/test",
managedClusteraddon: []runtime.Object{func() *addonapiv1alpha1.ManagedClusterAddOn {
addon := addontesting.NewHostedModeAddon("test", "cluster1", "hosting-cluster",
metav1.Condition{
Type: addonapiv1alpha1.ManagedClusterAddOnManifestApplied,
Status: metav1.ConditionTrue,
Reason: addonapiv1alpha1.AddonManifestAppliedReasonManifestsApplied,
Message: "manifests of addon are applied successfully",
},
metav1.Condition{
Type: addonapiv1alpha1.ManagedClusterAddOnHostingManifestApplied,
Status: metav1.ConditionTrue,
Reason: addonapiv1alpha1.AddonManifestAppliedReasonManifestsApplied,
Message: "hosting manifests of addon are applied successfully",
},
)
addon.Status.ConfigReferences = []addonapiv1alpha1.ConfigReference{
{
ConfigGroupResource: v1alpha1.ConfigGroupResource{Group: "core", Resource: "foo"},
DesiredConfig: &v1alpha1.ConfigSpecHash{
ConfigReferent: v1alpha1.ConfigReferent{Name: "test", Namespace: "open-cluster-management"},
SpecHash: "hashnew",
},
LastAppliedConfig: &v1alpha1.ConfigSpecHash{
ConfigReferent: v1alpha1.ConfigReferent{Name: "test", Namespace: "open-cluster-management"},
SpecHash: "",
},
},
}
return addon
}()},
clusterManagementAddon: []runtime.Object{
addontesting.NewClusterManagementAddon("test", "testcrd", "testcr").Build(),
},
work: []runtime.Object{
func() *workapiv1.ManifestWork {
work := addontesting.NewManifestWork(
"addon-test-deploy",
"hosting-cluster",
testingcommon.NewUnstructured("v1", "ConfigMap", "default", "test1"),
testingcommon.NewUnstructured("v1", "Deployment", "default", "test1"),
)
work.SetLabels(map[string]string{
addonapiv1alpha1.AddonLabelKey: "test",
addonapiv1alpha1.AddonNamespaceLabelKey: "cluster1",
})
work.SetAnnotations(map[string]string{
workapiv1.ManifestConfigSpecHashAnnotationKey: "{\"foo.core/open-cluster-management/test\":\"hash\"}",
})
work.Status.Conditions = []metav1.Condition{
{
Type: workapiv1.WorkApplied,
Status: metav1.ConditionTrue,
},
{
Type: workapiv1.WorkAvailable,
Status: metav1.ConditionTrue,
},
}
return work
}(),
},
validateAddonActions: func(t *testing.T, actions []clienttesting.Action) {
testingcommon.AssertActions(t, actions, "patch")
actual := actions[0].(clienttesting.PatchActionImpl).Patch
addOn := &addonapiv1alpha1.ManagedClusterAddOn{}
err := json.Unmarshal(actual, addOn)
if err != nil {
t.Fatal(err)
}
configCond := meta.FindStatusCondition(
addOn.Status.Conditions, addonapiv1alpha1.ManagedClusterAddOnConditionProgressing)
if !(configCond != nil &&
configCond.Reason == addonapiv1alpha1.ProgressingReasonInstalling &&
configCond.Status == metav1.ConditionTrue) {
t.Errorf("Condition Progressing is incorrect")
}
if len(addOn.Status.ConfigReferences) != 0 {
t.Errorf("ConfigReferences object is not correct: %v", addOn.Status.ConfigReferences)
}
},
},
{
name: "update managedclusteraddon to installing when work is not ready",
syncKey: "cluster1/test",
managedClusteraddon: []runtime.Object{func() *addonapiv1alpha1.ManagedClusterAddOn {
addon := addontesting.NewHostedModeAddon("test", "cluster1", "hosting-cluster",
metav1.Condition{
Type: addonapiv1alpha1.ManagedClusterAddOnManifestApplied,
Status: metav1.ConditionTrue,
Reason: addonapiv1alpha1.AddonManifestAppliedReasonManifestsApplied,
Message: "manifests of addon are applied successfully",
},
metav1.Condition{
Type: addonapiv1alpha1.ManagedClusterAddOnHostingManifestApplied,
Status: metav1.ConditionTrue,
Reason: addonapiv1alpha1.AddonManifestAppliedReasonManifestsApplied,
Message: "hosting manifests of addon are applied successfully",
},
)
addon.Status.ConfigReferences = []addonapiv1alpha1.ConfigReference{
{
ConfigGroupResource: v1alpha1.ConfigGroupResource{Group: "core", Resource: "foo"},
DesiredConfig: &v1alpha1.ConfigSpecHash{
ConfigReferent: v1alpha1.ConfigReferent{Name: "test", Namespace: "open-cluster-management"},
SpecHash: "hashnew",
},
LastAppliedConfig: &v1alpha1.ConfigSpecHash{
ConfigReferent: v1alpha1.ConfigReferent{Name: "test", Namespace: "open-cluster-management"},
SpecHash: "",
},
},
}
return addon
}()},
clusterManagementAddon: []runtime.Object{
addontesting.NewClusterManagementAddon("test", "testcrd", "testcr").Build(),
},
work: []runtime.Object{func() *workapiv1.ManifestWork {
work := addontesting.NewManifestWork(
"addon-test-deploy",
"hosting-cluster",
testingcommon.NewUnstructured("v1", "ConfigMap", "default", "test1"),
testingcommon.NewUnstructured("v1", "Deployment", "default", "test1"),
)
work.SetLabels(map[string]string{
addonapiv1alpha1.AddonLabelKey: "test",
addonapiv1alpha1.AddonNamespaceLabelKey: "cluster1",
})
work.SetAnnotations(map[string]string{
workapiv1.ManifestConfigSpecHashAnnotationKey: "{\"foo.core/open-cluster-management/test\":\"hashnew\"}",
})
work.Status.Conditions = []metav1.Condition{
{
Type: workapiv1.WorkApplied,
Status: metav1.ConditionFalse,
},
{
Type: workapiv1.WorkAvailable,
Status: metav1.ConditionTrue,
},
}
return work
}()},
validateAddonActions: func(t *testing.T, actions []clienttesting.Action) {
testingcommon.AssertActions(t, actions, "patch")
actual := actions[0].(clienttesting.PatchActionImpl).Patch
addOn := &addonapiv1alpha1.ManagedClusterAddOn{}
err := json.Unmarshal(actual, addOn)
if err != nil {
t.Fatal(err)
}
configCond := meta.FindStatusCondition(addOn.Status.Conditions, addonapiv1alpha1.ManagedClusterAddOnConditionProgressing)
if !(configCond != nil && configCond.Reason == addonapiv1alpha1.ProgressingReasonInstalling && configCond.Status == metav1.ConditionTrue) {
t.Errorf("Condition Progressing is incorrect")
}
if len(addOn.Status.ConfigReferences) != 0 {
t.Errorf("ConfigReferences object is not correct: %v", addOn.Status.ConfigReferences)
}
},
},
{
name: "update managedclusteraddon to uprading when work config spec not match",
syncKey: "cluster1/test",
managedClusteraddon: []runtime.Object{func() *addonapiv1alpha1.ManagedClusterAddOn {
addon := addontesting.NewHostedModeAddon("test", "cluster1", "hosting-cluster",
metav1.Condition{
Type: addonapiv1alpha1.ManagedClusterAddOnManifestApplied,
Status: metav1.ConditionTrue,
Reason: addonapiv1alpha1.AddonManifestAppliedReasonManifestsApplied,
Message: "manifests of addon are applied successfully",
},
metav1.Condition{
Type: addonapiv1alpha1.ManagedClusterAddOnHostingManifestApplied,
Status: metav1.ConditionTrue,
Reason: addonapiv1alpha1.AddonManifestAppliedReasonManifestsApplied,
Message: "hosting manifests of addon are applied successfully",
},
)
addon.Status.ConfigReferences = []addonapiv1alpha1.ConfigReference{
{
ConfigGroupResource: v1alpha1.ConfigGroupResource{Group: "core", Resource: "foo"},
DesiredConfig: &v1alpha1.ConfigSpecHash{
ConfigReferent: v1alpha1.ConfigReferent{Name: "test", Namespace: "open-cluster-management"},
SpecHash: "hashnew",
},
LastAppliedConfig: &v1alpha1.ConfigSpecHash{
ConfigReferent: v1alpha1.ConfigReferent{Name: "test", Namespace: "open-cluster-management"},
SpecHash: "hash",
},
},
}
return addon
}()},
clusterManagementAddon: []runtime.Object{
addontesting.NewClusterManagementAddon("test", "testcrd", "testcr").Build(),
},
work: []runtime.Object{func() *workapiv1.ManifestWork {
work := addontesting.NewManifestWork(
"addon-test-deploy",
"hosting-cluster",
testingcommon.NewUnstructured("v1", "ConfigMap", "default", "test1"),
testingcommon.NewUnstructured("v1", "Deployment", "default", "test1"),
)
work.SetLabels(map[string]string{
addonapiv1alpha1.AddonLabelKey: "test",
addonapiv1alpha1.AddonNamespaceLabelKey: "cluster1",
})
work.SetAnnotations(map[string]string{
workapiv1.ManifestConfigSpecHashAnnotationKey: "{\"foo.core/open-cluster-management/test\":\"hash\"}",
})
work.Status.Conditions = []metav1.Condition{
{
Type: workapiv1.WorkApplied,
Status: metav1.ConditionTrue,
},
{
Type: workapiv1.WorkAvailable,
Status: metav1.ConditionTrue,
},
}
return work
}()},
validateAddonActions: func(t *testing.T, actions []clienttesting.Action) {
testingcommon.AssertActions(t, actions, "patch")
actual := actions[0].(clienttesting.PatchActionImpl).Patch
addOn := &addonapiv1alpha1.ManagedClusterAddOn{}
err := json.Unmarshal(actual, addOn)
if err != nil {
t.Fatal(err)
}
configCond := meta.FindStatusCondition(
addOn.Status.Conditions, addonapiv1alpha1.ManagedClusterAddOnConditionProgressing)
if !(configCond != nil &&
configCond.Reason == addonapiv1alpha1.ProgressingReasonUpgrading &&
configCond.Status == metav1.ConditionTrue) {
t.Errorf("Condition Progressing is incorrect")
}
if len(addOn.Status.ConfigReferences) != 0 {
t.Errorf("ConfigReferences object is not correct: %v", addOn.Status.ConfigReferences)
}
},
},
{
name: "update managedclusteraddon to uprading when work is not ready",
syncKey: "cluster1/test",
managedClusteraddon: []runtime.Object{func() *addonapiv1alpha1.ManagedClusterAddOn {
addon := addontesting.NewHostedModeAddon("test", "cluster1", "hosting-cluster",
metav1.Condition{
Type: addonapiv1alpha1.ManagedClusterAddOnManifestApplied,
Status: metav1.ConditionTrue,
Reason: addonapiv1alpha1.AddonManifestAppliedReasonManifestsApplied,
Message: "manifests of addon are applied successfully",
},
metav1.Condition{
Type: addonapiv1alpha1.ManagedClusterAddOnHostingManifestApplied,
Status: metav1.ConditionTrue,
Reason: addonapiv1alpha1.AddonManifestAppliedReasonManifestsApplied,
Message: "hosting manifests of addon are applied successfully",
},
)
addon.Status.ConfigReferences = []addonapiv1alpha1.ConfigReference{
{
ConfigGroupResource: v1alpha1.ConfigGroupResource{Group: "core", Resource: "foo"},
DesiredConfig: &v1alpha1.ConfigSpecHash{
ConfigReferent: v1alpha1.ConfigReferent{Name: "test", Namespace: "open-cluster-management"},
SpecHash: "hashnew",
},
LastAppliedConfig: &v1alpha1.ConfigSpecHash{
ConfigReferent: v1alpha1.ConfigReferent{Name: "test", Namespace: "open-cluster-management"},
SpecHash: "hash",
},
},
}
return addon
}()},
clusterManagementAddon: []runtime.Object{
addontesting.NewClusterManagementAddon("test", "testcrd", "testcr").Build(),
},
work: []runtime.Object{func() *workapiv1.ManifestWork {
work := addontesting.NewManifestWork(
"addon-test-deploy",
"hosting-cluster",
testingcommon.NewUnstructured("v1", "ConfigMap", "default", "test1"),
testingcommon.NewUnstructured("v1", "Deployment", "default", "test1"),
)
work.SetLabels(map[string]string{
addonapiv1alpha1.AddonLabelKey: "test",
addonapiv1alpha1.AddonNamespaceLabelKey: "cluster1",
})
work.SetAnnotations(map[string]string{
workapiv1.ManifestConfigSpecHashAnnotationKey: "{\"foo.core/open-cluster-management/test\":\"hashnew\"}",
})
work.Status.Conditions = []metav1.Condition{
{
Type: workapiv1.WorkApplied,
Status: metav1.ConditionTrue,
},
{
Type: workapiv1.WorkAvailable,
Status: metav1.ConditionFalse,
},
}
return work
}()},
validateAddonActions: func(t *testing.T, actions []clienttesting.Action) {
testingcommon.AssertActions(t, actions, "patch")
actual := actions[0].(clienttesting.PatchActionImpl).Patch
addOn := &addonapiv1alpha1.ManagedClusterAddOn{}
err := json.Unmarshal(actual, addOn)
if err != nil {
t.Fatal(err)
}
configCond := meta.FindStatusCondition(
addOn.Status.Conditions, addonapiv1alpha1.ManagedClusterAddOnConditionProgressing)
if !(configCond != nil &&
configCond.Reason == addonapiv1alpha1.ProgressingReasonUpgrading &&
configCond.Status == metav1.ConditionTrue) {
t.Errorf("Condition Progressing is incorrect")
}
if len(addOn.Status.ConfigReferences) != 0 {
t.Errorf("ConfigReferences object is not correct: %v", addOn.Status.ConfigReferences)
}
},
},
{
name: "update managedclusteraddon to install succeed",
syncKey: "cluster1/test",
managedClusteraddon: []runtime.Object{func() *addonapiv1alpha1.ManagedClusterAddOn {
addon := addontesting.NewHostedModeAddon("test", "cluster1", "hosting-cluster",
metav1.Condition{
Type: addonapiv1alpha1.ManagedClusterAddOnManifestApplied,
Status: metav1.ConditionTrue,
Reason: addonapiv1alpha1.AddonManifestAppliedReasonManifestsApplied,
Message: "manifests of addon are applied successfully",
},
metav1.Condition{
Type: addonapiv1alpha1.ManagedClusterAddOnHostingManifestApplied,
Status: metav1.ConditionTrue,
Reason: addonapiv1alpha1.AddonManifestAppliedReasonManifestsApplied,
Message: "hosting manifests of addon are applied successfully",
},
)
addon.Status.ConfigReferences = []addonapiv1alpha1.ConfigReference{
{
ConfigGroupResource: v1alpha1.ConfigGroupResource{Group: "core", Resource: "foo"},
DesiredConfig: &v1alpha1.ConfigSpecHash{
ConfigReferent: v1alpha1.ConfigReferent{Name: "test", Namespace: "open-cluster-management"},
SpecHash: "hashnew",
},
LastAppliedConfig: &v1alpha1.ConfigSpecHash{
ConfigReferent: v1alpha1.ConfigReferent{Name: "test", Namespace: "open-cluster-management"},
SpecHash: "",
},
},
}
return addon
}()},
clusterManagementAddon: []runtime.Object{
addontesting.NewClusterManagementAddon("test", "testcrd", "testcr").Build(),
},
work: []runtime.Object{func() *workapiv1.ManifestWork {
work := addontesting.NewManifestWork(
"addon-test-deploy",
"hosting-cluster",
testingcommon.NewUnstructured("v1", "ConfigMap", "default", "test1"),
testingcommon.NewUnstructured("v1", "Deployment", "default", "test1"),
)
work.SetLabels(map[string]string{
addonapiv1alpha1.AddonLabelKey: "test",
addonapiv1alpha1.AddonNamespaceLabelKey: "cluster1",
})
work.SetAnnotations(map[string]string{
workapiv1.ManifestConfigSpecHashAnnotationKey: "{\"foo.core/open-cluster-management/test\":\"hashnew\"}",
})
work.Status.Conditions = []metav1.Condition{
{
Type: workapiv1.WorkApplied,
Status: metav1.ConditionTrue,
},
{
Type: workapiv1.WorkAvailable,
Status: metav1.ConditionTrue,
},
}
return work
}()},
validateAddonActions: func(t *testing.T, actions []clienttesting.Action) {
testingcommon.AssertActions(t, actions, "patch")
actual := actions[0].(clienttesting.PatchActionImpl).Patch
addOn := &addonapiv1alpha1.ManagedClusterAddOn{}
err := json.Unmarshal(actual, addOn)
if err != nil {
t.Fatal(err)
}
configCond := meta.FindStatusCondition(
addOn.Status.Conditions, addonapiv1alpha1.ManagedClusterAddOnConditionProgressing)
if !(configCond != nil &&
configCond.Reason == addonapiv1alpha1.ProgressingReasonInstallSucceed &&
configCond.Status == metav1.ConditionFalse) {
t.Errorf("Condition Progressing is incorrect")
}
if len(addOn.Status.ConfigReferences) != 1 {
t.Errorf("ConfigReferences object is not correct: %v", addOn.Status.ConfigReferences)
}
if addOn.Status.ConfigReferences[0].LastAppliedConfig.SpecHash !=
addOn.Status.ConfigReferences[0].DesiredConfig.SpecHash {
t.Errorf("LastAppliedConfig object is not correct: %v",
addOn.Status.ConfigReferences[0].LastAppliedConfig.SpecHash)
}
},
},
{
name: "update managedclusteraddon to upgrade succeed",
syncKey: "cluster1/test",
managedClusteraddon: []runtime.Object{func() *addonapiv1alpha1.ManagedClusterAddOn {
addon := addontesting.NewHostedModeAddon("test", "cluster1", "hosting-cluster",
metav1.Condition{
Type: addonapiv1alpha1.ManagedClusterAddOnManifestApplied,
Status: metav1.ConditionTrue,
Reason: addonapiv1alpha1.AddonManifestAppliedReasonManifestsApplied,
Message: "manifests of addon are applied successfully",
},
metav1.Condition{
Type: addonapiv1alpha1.ManagedClusterAddOnHostingManifestApplied,
Status: metav1.ConditionTrue,
Reason: addonapiv1alpha1.AddonManifestAppliedReasonManifestsApplied,
Message: "hosting manifests of addon are applied successfully",
},
)
addon.Status.ConfigReferences = []addonapiv1alpha1.ConfigReference{
{
ConfigGroupResource: v1alpha1.ConfigGroupResource{Group: "core", Resource: "foo"},
DesiredConfig: &v1alpha1.ConfigSpecHash{
ConfigReferent: v1alpha1.ConfigReferent{Name: "test", Namespace: "open-cluster-management"},
SpecHash: "hashnew",
},
LastAppliedConfig: &v1alpha1.ConfigSpecHash{
ConfigReferent: v1alpha1.ConfigReferent{Name: "test", Namespace: "open-cluster-management"},
SpecHash: "hash",
},
},
}
return addon
}()},
clusterManagementAddon: []runtime.Object{
addontesting.NewClusterManagementAddon("test", "testcrd", "testcr").Build(),
},
work: []runtime.Object{func() *workapiv1.ManifestWork {
work := addontesting.NewManifestWork(
"addon-test-deploy",
"hosting-cluster",
testingcommon.NewUnstructured("v1", "ConfigMap", "default", "test1"),
testingcommon.NewUnstructured("v1", "Deployment", "default", "test1"),
)
work.SetLabels(map[string]string{
addonapiv1alpha1.AddonLabelKey: "test",
addonapiv1alpha1.AddonNamespaceLabelKey: "cluster1",
})
work.SetAnnotations(map[string]string{
workapiv1.ManifestConfigSpecHashAnnotationKey: "{\"foo.core/open-cluster-management/test\":\"hashnew\"}",
})
work.Status.Conditions = []metav1.Condition{
{
Type: workapiv1.WorkApplied,
Status: metav1.ConditionTrue,
},
{
Type: workapiv1.WorkAvailable,
Status: metav1.ConditionTrue,
},
}
return work
}()},
validateAddonActions: func(t *testing.T, actions []clienttesting.Action) {
testingcommon.AssertActions(t, actions, "patch")
actual := actions[0].(clienttesting.PatchActionImpl).Patch
addOn := &addonapiv1alpha1.ManagedClusterAddOn{}
err := json.Unmarshal(actual, addOn)
if err != nil {
t.Fatal(err)
}
configCond := meta.FindStatusCondition(
addOn.Status.Conditions, addonapiv1alpha1.ManagedClusterAddOnConditionProgressing)
if !(configCond != nil &&
configCond.Reason == addonapiv1alpha1.ProgressingReasonUpgradeSucceed &&
configCond.Status == metav1.ConditionFalse) {
t.Errorf("Condition Progressing is incorrect")
}
if len(addOn.Status.ConfigReferences) != 1 {
t.Errorf("ConfigReferences object is not correct: %v", addOn.Status.ConfigReferences)
}
if addOn.Status.ConfigReferences[0].LastAppliedConfig.SpecHash !=
addOn.Status.ConfigReferences[0].DesiredConfig.SpecHash {
t.Errorf("LastAppliedConfig object is not correct: %v",
addOn.Status.ConfigReferences[0].LastAppliedConfig.SpecHash)
}
},
},
{
name: "update managedclusteraddon to configuration unsupported...",
syncKey: "cluster1/test",
managedClusteraddon: []runtime.Object{
func() *addonapiv1alpha1.ManagedClusterAddOn {
addon := addontesting.NewHostedModeAddon("test", "cluster1", "hosting-cluster",
metav1.Condition{
Type: addonapiv1alpha1.ManagedClusterAddOnManifestApplied,
Status: metav1.ConditionTrue,
Reason: addonapiv1alpha1.AddonManifestAppliedReasonManifestsApplied,
Message: "manifests of addon are applied successfully",
},
metav1.Condition{
Type: addonapiv1alpha1.ManagedClusterAddOnHostingManifestApplied,
Status: metav1.ConditionTrue,
Reason: addonapiv1alpha1.AddonManifestAppliedReasonManifestsApplied,
Message: "hosting manifests of addon are applied successfully",
},
)
addon.Spec.Configs = []addonapiv1alpha1.AddOnConfig{
{
ConfigGroupResource: addonapiv1alpha1.ConfigGroupResource{
Group: "config1.test",
Resource: "config1",
},
ConfigReferent: addonapiv1alpha1.ConfigReferent{
Namespace: "cluster1",
Name: "override",
},
},
}
addon.Status.SupportedConfigs = []addonapiv1alpha1.ConfigGroupResource{
{
Group: "configs.test",
Resource: "testconfigs",
},
}
return addon
}(),
},
clusterManagementAddon: []runtime.Object{
addontesting.NewClusterManagementAddon("test", "testcrd", "testcr").Build(),
},
work: []runtime.Object{},
validateAddonActions: func(t *testing.T, actions []clienttesting.Action) {
testingcommon.AssertActions(t, actions, "patch")
patch := actions[0].(clienttesting.PatchAction).GetPatch()
addOn := &addonapiv1alpha1.ManagedClusterAddOn{}
err := json.Unmarshal(patch, addOn)
if err != nil {
t.Fatal(err)
}
configCond := meta.FindStatusCondition(addOn.Status.Conditions, addonapiv1alpha1.ManagedClusterAddOnConditionProgressing)
if !(configCond != nil && configCond.Reason == addonapiv1alpha1.ProgressingReasonConfigurationUnsupported && configCond.Status == metav1.ConditionFalse) {
t.Errorf("Condition Progressing is incorrect")
}
},
},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
fakeAddonClient := fakeaddon.NewSimpleClientset(c.managedClusteraddon...)
fakeWorkClient := fakework.NewSimpleClientset()
addonInformers := addoninformers.NewSharedInformerFactory(fakeAddonClient, 10*time.Minute)
workInformers := workinformers.NewSharedInformerFactory(fakeWorkClient, 10*time.Minute)
for _, obj := range c.managedClusteraddon {
if err := addonInformers.Addon().V1alpha1().ManagedClusterAddOns().Informer().GetStore().
Add(obj); err != nil {
t.Fatal(err)
}
}
for _, obj := range c.clusterManagementAddon {
if err := addonInformers.Addon().V1alpha1().ClusterManagementAddOns().Informer().GetStore().
Add(obj); err != nil {
t.Fatal(err)
}
}
for _, obj := range c.work {
if err := workInformers.Work().V1().ManifestWorks().Informer().GetStore().Add(obj); err != nil {
t.Fatal(err)
}
}
syncContext := testingcommon.NewFakeSyncContext(t, c.syncKey)
recorder := syncContext.Recorder()
controller := NewAddonProgressingController(
fakeAddonClient,
addonInformers.Addon().V1alpha1().ManagedClusterAddOns(),
addonInformers.Addon().V1alpha1().ClusterManagementAddOns(),
workInformers.Work().V1().ManifestWorks(),
utils.ManagedBySelf(map[string]agent.AgentAddon{"test": nil}),
recorder,
)
err := controller.Sync(context.TODO(), syncContext)
if err != nil {
t.Errorf("expected no error when sync: %v", err)
}
c.validateAddonActions(t, fakeAddonClient.Actions())
})
}
}
@@ -15,8 +15,6 @@ import (
const (
defaultAddOnInstallationNamespace = "open-cluster-management-agent-addon"
// hostingClusterNameAnnotation is the annotation for indicating the hosting cluster name
hostingClusterNameAnnotation = "addon.open-cluster-management.io/hosting-cluster-name"
)
// registrationConfig contains necessary information for addon registration
@@ -76,7 +74,7 @@ func getAddOnInstallationNamespace(addOn *addonv1alpha1.ManagedClusterAddOn) str
// isAddonRunningOutsideManagedCluster returns whether the addon agent is running on the managed cluster
func isAddonRunningOutsideManagedCluster(addOn *addonv1alpha1.ManagedClusterAddOn) bool {
hostingCluster, ok := addOn.Annotations[hostingClusterNameAnnotation]
hostingCluster, ok := addOn.Annotations[addonv1alpha1.HostingClusterNameAnnotationKey]
if ok && len(hostingCluster) != 0 {
return true
}
@@ -85,7 +85,7 @@ func TestGetRegistrationConfigs(t *testing.T) {
Namespace: testinghelpers.TestManagedClusterName,
Name: addOnName,
Annotations: map[string]string{
hostingClusterNameAnnotation: "test",
addonv1alpha1.HostingClusterNameAnnotationKey: "test",
},
},
Spec: addonv1alpha1.ManagedClusterAddOnSpec{
@@ -296,7 +296,7 @@ func TestSync(t *testing.T) {
Namespace: testinghelpers.TestManagedClusterName,
Name: "test",
Annotations: map[string]string{
hostingClusterNameAnnotation: "cluster1",
addonv1alpha1.HostingClusterNameAnnotationKey: "cluster1",
},
},
Spec: addonv1alpha1.ManagedClusterAddOnSpec{
@@ -437,7 +437,7 @@ func newManagedClusterAddOn(namespace, name string, registrations []addonv1alpha
}
if hostedMode {
addon.SetAnnotations(map[string]string{hostingClusterNameAnnotation: "test"})
addon.SetAnnotations(map[string]string{addonv1alpha1.HostingClusterNameAnnotationKey: "test"})
}
return addon
}