Feat: support use update instead of patch for apply (#4592)

Signed-off-by: Somefive <yd219913@alibaba-inc.com>
This commit is contained in:
Somefive
2022-08-10 21:30:43 +08:00
committed by GitHub
parent e63377092a
commit d7919110cd
3 changed files with 80 additions and 8 deletions
+12
View File
@@ -43,6 +43,17 @@ const (
// DisableReferObjectsFromURL if set, the url ref objects will be disallowed
DisableReferObjectsFromURL featuregate.Feature = "DisableReferObjectsFromURL"
// ApplyResourceByUpdate enforces the modification of resource through update requests.
// If not set, the resource modification will use patch requests (three-way-strategy-merge-patch).
// The side effect of enabling this feature is that the request traffic will increase due to
// the increase of bytes transferred and the more frequent resource mutation failure due to the
// potential conflicts.
// If set, KubeVela controller will enforce strong restriction on the managed resource that external
// system would be unable to make modifications to the KubeVela managed resource. In other words,
// no merge for modifications from multiple sources. Only KubeVela keeps the Source-of-Truth for the
// resource.
ApplyResourceByUpdate featuregate.Feature = "ApplyResourceByUpdate"
// Edge Features
// AuthenticateApplication enable the authentication for application
@@ -58,6 +69,7 @@ var defaultFeatureGates = map[featuregate.Feature]featuregate.FeatureSpec{
LegacyComponentRevision: {Default: false, PreRelease: featuregate.Alpha},
LegacyResourceOwnerValidation: {Default: false, PreRelease: featuregate.Alpha},
DisableReferObjectsFromURL: {Default: false, PreRelease: featuregate.Alpha},
ApplyResourceByUpdate: {Default: false, PreRelease: featuregate.Alpha},
AuthenticateApplication: {Default: false, PreRelease: featuregate.Alpha},
}
+30 -8
View File
@@ -170,15 +170,26 @@ func (a *APIApplicator) Apply(ctx context.Context, desired client.Object, ao ...
return nil
}
loggingApply("patching object", desired)
patch, err := a.patcher.patch(existing, desired, applyAct)
if err != nil {
return errors.Wrap(err, "cannot calculate patch by computing a three way diff")
switch {
case utilfeature.DefaultMutableFeatureGate.Enabled(features.ApplyResourceByUpdate) && isUpdatableResource(desired):
loggingApply("updating object", desired)
desired.SetResourceVersion(existing.GetResourceVersion())
var options []client.UpdateOption
if applyAct.dryRun {
options = append(options, client.DryRunAll)
}
return errors.Wrapf(a.c.Update(ctx, desired, options...), "cannot update object")
default:
loggingApply("patching object", desired)
patch, err := a.patcher.patch(existing, desired, applyAct)
if err != nil {
return errors.Wrap(err, "cannot calculate patch by computing a three way diff")
}
if applyAct.dryRun {
return errors.Wrapf(a.c.Patch(ctx, desired, patch, client.DryRunAll), "cannot patch object")
}
return errors.Wrapf(a.c.Patch(ctx, desired, patch), "cannot patch object")
}
if applyAct.dryRun {
return errors.Wrapf(a.c.Patch(ctx, desired, patch, client.DryRunAll), "cannot patch object")
}
return errors.Wrapf(a.c.Patch(ctx, desired, patch), "cannot patch object")
}
func generateRenderHash(desired client.Object) (string, error) {
@@ -397,3 +408,14 @@ func DryRunAll() ApplyOption {
return nil
}
}
// isUpdatableResource check whether the resource is updatable
// Resource like v1.Service cannot unset the spec field (the ip spec is filled by service controller)
func isUpdatableResource(desired client.Object) bool {
// nolint
switch desired.GetObjectKind().GroupVersionKind() {
case corev1.SchemeGroupVersion.WithKind("Service"):
return false
}
return true
}
+38
View File
@@ -18,6 +18,8 @@ package apply
import (
"context"
"encoding/json"
"fmt"
"strings"
. "github.com/onsi/ginkgo"
@@ -25,6 +27,7 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"sigs.k8s.io/controller-runtime/pkg/client"
appsv1 "k8s.io/api/apps/v1"
@@ -34,6 +37,7 @@ import (
"k8s.io/utils/pointer"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
"github.com/oam-dev/kubevela/pkg/features"
"github.com/oam-dev/kubevela/pkg/oam"
oamutil "github.com/oam-dev/kubevela/pkg/oam/util"
)
@@ -166,6 +170,40 @@ var _ = Describe("Test apply", func() {
}))
Expect(rawClient.Delete(ctx, cm2)).Should(Succeed())
})
It("Test apply resources with external modifier", func() {
deploy.SetGroupVersionKind(appsv1.SchemeGroupVersion.WithKind("Deployment"))
originalDeploy := deploy.DeepCopy()
bs, err := json.Marshal(deploy)
Expect(err).Should(Succeed())
deploy.SetAnnotations(map[string]string{oam.AnnotationLastAppliedConfig: string(bs)})
modifiedDeploy := deploy.DeepCopy()
modifiedDeploy.Spec.Template.Spec.Containers = append(modifiedDeploy.Spec.Template.Spec.Containers, corev1.Container{
Name: "added-by-external-modifier",
Image: "busybox",
})
Expect(rawClient.Update(ctx, modifiedDeploy)).Should(Succeed())
By("Test patch")
Expect(utilfeature.DefaultMutableFeatureGate.Set(fmt.Sprintf("%s=false", features.ApplyResourceByUpdate))).Should(Succeed())
Expect(rawClient.Get(ctx, client.ObjectKeyFromObject(deploy), deploy)).Should(Succeed())
copy1 := originalDeploy.DeepCopy()
copy1.SetResourceVersion(deploy.ResourceVersion)
Expect(k8sApplicator.Apply(ctx, copy1)).Should(Succeed())
Expect(rawClient.Get(ctx, client.ObjectKeyFromObject(deploy), deploy)).Should(Succeed())
Expect(len(deploy.Spec.Template.Spec.Containers)).Should(Equal(2))
By("Test update")
Expect(utilfeature.DefaultMutableFeatureGate.Set(fmt.Sprintf("%s=true", features.ApplyResourceByUpdate))).Should(Succeed())
Expect(rawClient.Get(ctx, client.ObjectKeyFromObject(deploy), deploy)).Should(Succeed())
copy2 := originalDeploy.DeepCopy()
copy2.SetResourceVersion(deploy.ResourceVersion)
Expect(k8sApplicator.Apply(ctx, copy2)).Should(Succeed())
Expect(rawClient.Get(ctx, client.ObjectKeyFromObject(deploy), deploy)).Should(Succeed())
Expect(len(deploy.Spec.Template.Spec.Containers)).Should(Equal(1))
Expect(utilfeature.DefaultMutableFeatureGate.Set(fmt.Sprintf("%s=false", features.ApplyResourceByUpdate))).Should(Succeed())
})
})
})