[go: nahoru, domu]

Skip to content
This repository has been archived by the owner on Jun 8, 2022. It is now read-only.

Commit

Permalink
Merge pull request #298 from captainroy-hy/switch-reconcile
Browse files Browse the repository at this point in the history
add ApplyOnceOnly switch for production running requirement
  • Loading branch information
wonderflow committed Nov 23, 2020
2 parents 2cf8f63 + fe987c4 commit 40491a4
Show file tree
Hide file tree
Showing 14 changed files with 418 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ spec:
args:
- "--metrics-addr=:8080"
- "--enable-leader-election"
- "--apply-once- .Values.applyOnceOnly }}"
{{ if .Values.useWebhook }}
- "--use-webhook=true"
- "--webhook-port={{ .Values.webhookService.port }}"
Expand Down
3 changes: 2 additions & 1 deletion charts/oam-kubernetes-runtime/values.yaml.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

replicaCount: 1
useWebhook: false
applyOnceOnly: false
image:
repository: crossplane/oam-kubernetes-runtime
tag: %%VERSION%%
Expand Down Expand Up @@ -56,4 +57,4 @@ certificate:
certificateName: serving-cert
secretName: webhook-server-cert
mountPath: /etc/k8s-webhook-certs
caBundle: replace-me
caBundle: replace-me
5 changes: 5 additions & 0 deletions cmd/oam-kubernetes-runtime/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ func main() {
flag.BoolVar(&logCompress, "log-compress", true, "Enable compression on the rotated logs.")
flag.IntVar(&controllerArgs.RevisionLimit, "revision-limit", 50,
"RevisionLimit is the maximum number of revisions that will be maintained. The default value is 50.")
flag.BoolVar(&controllerArgs.ApplyOnceOnly, "apply-once-only", false,
"For the purpose of some production environment that workload or trait should not be affected if no spec change")
flag.Parse()

// setup logging
Expand Down Expand Up @@ -100,6 +102,9 @@ func main() {
os.Exit(1)
}
oamLog.Info("starting the controller manager")
if controllerArgs.ApplyOnceOnly {
oamLog.Info("applyOnceOnly is enabled that means workload or trait only apply once if no spec change even they are changed by others")
}
if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
oamLog.Error(err, "problem running manager")
os.Exit(1)
Expand Down
4 changes: 4 additions & 0 deletions pkg/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,8 @@ type Args struct {
// RevisionLimit is the maximum number of revisions that will be maintained.
// The default value is 50.
RevisionLimit int

// ApplyOnceOnly indicates whether workloads and traits should be
// affected if no spec change is made in the ApplicationConfiguration.
ApplyOnceOnly bool
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"time"

"github.com/pkg/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
ctrl "sigs.k8s.io/controller-runtime"
Expand Down Expand Up @@ -97,21 +98,23 @@ func Setup(mgr ctrl.Manager, args controller.Args, l logging.Logger) error {
}).
Complete(NewReconciler(mgr, dm,
WithLogger(l.WithValues("controller", name)),
WithRecorder(event.NewAPIRecorder(mgr.GetEventRecorderFor(name)))))
WithRecorder(event.NewAPIRecorder(mgr.GetEventRecorderFor(name))),
WithApplyOnceOnly(args.ApplyOnceOnly)))
}

// An OAMApplicationReconciler reconciles OAM ApplicationConfigurations by rendering and
// instantiating their Components and Traits.
type OAMApplicationReconciler struct {
client client.Client
components ComponentRenderer
workloads WorkloadApplicator
gc GarbageCollector
scheme *runtime.Scheme
log logging.Logger
record event.Recorder
preHooks map[string]ControllerHooks
postHooks map[string]ControllerHooks
client client.Client
components ComponentRenderer
workloads WorkloadApplicator
gc GarbageCollector
scheme *runtime.Scheme
log logging.Logger
record event.Recorder
preHooks map[string]ControllerHooks
postHooks map[string]ControllerHooks
applyOnceOnly bool
}

// A ReconcilerOption configures a Reconciler.
Expand Down Expand Up @@ -168,6 +171,14 @@ func WithPosthook(name string, hook ControllerHooks) ReconcilerOption {
}
}

// WithApplyOnceOnly indicates whether workloads and traits should be
// affected if no spec change is made in the ApplicationConfiguration.
func WithApplyOnceOnly(applyOnceOnly bool) ReconcilerOption {
return func(r *OAMApplicationReconciler) {
r.applyOnceOnly = applyOnceOnly
}
}

// NewReconciler returns an OAMApplicationReconciler that reconciles ApplicationConfigurations
// by rendering and instantiating their Components and Traits.
func NewReconciler(m ctrl.Manager, dm discoverymapper.DiscoveryMapper, o ...ReconcilerOption) *OAMApplicationReconciler {
Expand Down Expand Up @@ -279,7 +290,11 @@ func (r *OAMApplicationReconciler) Reconcile(req reconcile.Request) (result reco
log.Debug("Successfully rendered components", "workloads", len(workloads))
r.record.Event(ac, event.Normal(reasonRenderComponents, "Successfully rendered components", "workloads", strconv.Itoa(len(workloads))))

if err := r.workloads.Apply(ctx, ac.Status.Workloads, workloads, resource.MustBeControllableBy(ac.GetUID())); err != nil {
applyOpts := []resource.ApplyOption{resource.MustBeControllableBy(ac.GetUID())}
if r.applyOnceOnly {
applyOpts = append(applyOpts, applyOnceOnly())
}
if err := r.workloads.Apply(ctx, ac.Status.Workloads, workloads, applyOpts...); err != nil {
log.Debug("Cannot apply components", "error", err, "requeue-after", time.Now().Add(shortWait))
r.record.Event(ac, event.Warning(reasonCannotApplyComponents, err))
ac.SetConditions(v1alpha1.ReconcileError(errors.Wrap(err, errApplyComponents)))
Expand Down Expand Up @@ -544,3 +559,44 @@ func eligible(namespace string, ws []v1alpha2.WorkloadStatus, w []Workload) []un

return eligible
}

// GenerationUnchanged indicates the resource being applied has no generation changed
// comparing to the existing one.
type GenerationUnchanged struct{}

func (e *GenerationUnchanged) Error() string {
return fmt.Sprint("apply-only-once enabled,",
"and detect generation in the annotation unchanged, will not apply.",
"Please ignore this error in other logic.")
}

func applyOnceOnly() resource.ApplyOption {
return func(ctx context.Context, current, desired runtime.Object) error {
// ApplyOption only works for update/patch operation and will be ignored
// if the object doesn't exist before.
c, _ := current.(metav1.Object)
d, _ := desired.(metav1.Object)
if c == nil || d == nil {
return errors.Errorf("invalid object being applied: %q ",
desired.GetObjectKind().GroupVersionKind())
}
cLabels, dLabels := c.GetLabels(), d.GetLabels()
if dLabels[oam.LabelOAMResourceType] == oam.ResourceTypeWorkload ||
dLabels[oam.LabelOAMResourceType] == oam.ResourceTypeTrait {
// check whether spec changes occur on the workload or trait,
// according to annotations and lables
if c.GetAnnotations()[oam.AnnotationAppGeneration] !=
d.GetAnnotations()[oam.AnnotationAppGeneration] {
return nil
}
if cLabels[oam.LabelAppComponentRevision] != dLabels[oam.LabelAppComponentRevision] ||
cLabels[oam.LabelAppComponent] != dLabels[oam.LabelAppComponent] ||
cLabels[oam.LabelAppName] != dLabels[oam.LabelAppName] {
return nil
}
// return an error to abort current apply
return &GenerationUnchanged{}
}
return nil
}
}
12 changes: 10 additions & 2 deletions pkg/controller/v1alpha2/applicationconfiguration/apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,11 @@ func (a *workloads) Apply(ctx context.Context, status []v1alpha2.WorkloadStatus,
if !wl.HasDep {
err := a.patchingClient.Apply(ctx, wl.Workload, ao...)
if err != nil {
return errors.Wrapf(err, errFmtApplyWorkload, wl.Workload.GetName())
if _, ok := err.(*GenerationUnchanged); !ok {
// GenerationUnchanged only aborts applying current workload
// but not blocks the whole reconciliation through returning an error
return errors.Wrapf(err, errFmtApplyWorkload, wl.Workload.GetName())
}
}
}
for _, trait := range wl.Traits {
Expand All @@ -99,7 +103,11 @@ func (a *workloads) Apply(ctx context.Context, status []v1alpha2.WorkloadStatus,
}
t := trait.Object
if err := a.updatingClient.Apply(ctx, &trait.Object, ao...); err != nil {
return errors.Wrapf(err, errFmtApplyTrait, t.GetAPIVersion(), t.GetKind(), t.GetName())
if _, ok := err.(*GenerationUnchanged); !ok {
// GenerationUnchanged only aborts applying current trait
// but not blocks the whole reconciliation through returning an error
return errors.Wrapf(err, errFmtApplyTrait, t.GetAPIVersion(), t.GetKind(), t.GetName())
}
}
}
workloadRef := runtimev1alpha1.TypedReference{
Expand Down
Loading

0 comments on commit 40491a4

Please sign in to comment.