From e890ab6227de8fe4d084775223defa9f77f9872c Mon Sep 17 00:00:00 2001 From: Cesar Wong Date: Tue, 12 Nov 2019 09:30:04 +0100 Subject: [PATCH] Use exclude identifier and annotation to skip certain manifests --- pkg/cvo/cvo.go | 8 ++++++++ pkg/cvo/cvo_scenarios_test.go | 1 + pkg/cvo/sync_worker.go | 31 +++++++++++++++++++---------- pkg/start/start.go | 10 ++++++++++ pkg/start/start_integration_test.go | 8 ++++---- 5 files changed, 44 insertions(+), 14 deletions(-) diff --git a/pkg/cvo/cvo.go b/pkg/cvo/cvo.go index 94cb6a86e1..f2d2d77393 100644 --- a/pkg/cvo/cvo.go +++ b/pkg/cvo/cvo.go @@ -139,6 +139,10 @@ type Operator struct { // lastAtLock guards access to controller memory about the sync loop lastAtLock sync.Mutex lastResourceVersion int64 + + // exclude is an optional identifier used to exclude certain manifests + // via annotation + exclude string } // New returns a new cluster version operator. @@ -156,6 +160,7 @@ func New( client clientset.Interface, kubeClient kubernetes.Interface, enableMetrics bool, + exclude string, ) *Operator { eventBroadcaster := record.NewBroadcaster() eventBroadcaster.StartLogging(klog.Infof) @@ -181,6 +186,8 @@ func New( queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "clusterversion"), availableUpdatesQueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "availableupdates"), upgradeableQueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "upgradeable"), + + exclude: exclude, } cvInformer.Informer().AddEventHandler(optr.eventHandler()) @@ -246,6 +253,7 @@ func (optr *Operator) InitializeFromPayload(restConfig *rest.Config, burstRestCo Factor: 1.3, Steps: 3, }, + optr.exclude, ) return nil diff --git a/pkg/cvo/cvo_scenarios_test.go b/pkg/cvo/cvo_scenarios_test.go index bfa74afb29..053c23666d 100644 --- a/pkg/cvo/cvo_scenarios_test.go +++ b/pkg/cvo/cvo_scenarios_test.go @@ -90,6 +90,7 @@ func setupCVOTest(payloadDir string) (*Operator, map[string]runtime.Object, *fak wait.Backoff{ Steps: 1, }, + "", ) o.configSync = worker diff --git a/pkg/cvo/sync_worker.go b/pkg/cvo/sync_worker.go index 474bd7502d..5b20a47a04 100644 --- a/pkg/cvo/sync_worker.go +++ b/pkg/cvo/sync_worker.go @@ -126,11 +126,11 @@ func (w SyncWorkerStatus) DeepCopy() *SyncWorkerStatus { // syncOnce() returns nil -> Reconciling // type SyncWorker struct { - backoff wait.Backoff - retriever PayloadRetriever - builder payload.ResourceBuilder - preconditions precondition.List - reconciling bool + backoff wait.Backoff + retriever PayloadRetriever + builder payload.ResourceBuilder + preconditions precondition.List + reconciling bool // minimumReconcileInterval is the minimum time between reconcile attempts, and is // used to define the maximum backoff interval when syncOnce() returns an error. @@ -148,11 +148,16 @@ type SyncWorker struct { // updated by the run method only payload *payload.Update + + // exclude is an identifier used to determine which + // manifests should be excluded based on an annotation + // of the form exclude.release.openshift.io/=true + exclude string } // NewSyncWorker initializes a ConfigSyncWorker that will retrieve payloads to disk, apply them via builder // to a server, and obey limits about how often to reconcile or retry on errors. -func NewSyncWorker(retriever PayloadRetriever, builder payload.ResourceBuilder, reconcileInterval time.Duration, backoff wait.Backoff) *SyncWorker { +func NewSyncWorker(retriever PayloadRetriever, builder payload.ResourceBuilder, reconcileInterval time.Duration, backoff wait.Backoff, exclude string) *SyncWorker { return &SyncWorker{ retriever: retriever, builder: builder, @@ -165,14 +170,16 @@ func NewSyncWorker(retriever PayloadRetriever, builder payload.ResourceBuilder, // Status() or use the result of calling Update() instead because the channel can be out of date // if the reader is not fast enough. report: make(chan SyncWorkerStatus, 500), + + exclude: exclude, } } // NewSyncWorkerWithPreconditions initializes a ConfigSyncWorker that will retrieve payloads to disk, apply them via builder // to a server, and obey limits about how often to reconcile or retry on errors. // It allows providing preconditions for loading payload. -func NewSyncWorkerWithPreconditions(retriever PayloadRetriever, builder payload.ResourceBuilder, preconditions precondition.List, reconcileInterval time.Duration, backoff wait.Backoff) *SyncWorker { - worker := NewSyncWorker(retriever, builder, reconcileInterval, backoff) +func NewSyncWorkerWithPreconditions(retriever PayloadRetriever, builder payload.ResourceBuilder, preconditions precondition.List, reconcileInterval time.Duration, backoff wait.Backoff, exclude string) *SyncWorker { + worker := NewSyncWorker(retriever, builder, reconcileInterval, backoff, exclude) worker.preconditions = preconditions return worker } @@ -614,7 +621,7 @@ func (w *SyncWorker) apply(ctx context.Context, payloadUpdate *payload.Update, w klog.V(4).Infof("Running sync for %s", task) klog.V(5).Infof("Manifest: %s", string(task.Manifest.Raw)) - ov, ok := getOverrideForManifest(work.Overrides, task.Manifest) + ov, ok := getOverrideForManifest(work.Overrides, w.exclude, task.Manifest) if ok && ov.Unmanaged { klog.V(4).Infof("Skipping %s as unmanaged", task) continue @@ -906,7 +913,7 @@ func newMultipleError(errs []error) error { } // getOverrideForManifest returns the override and true when override exists for manifest. -func getOverrideForManifest(overrides []configv1.ComponentOverride, manifest *lib.Manifest) (configv1.ComponentOverride, bool) { +func getOverrideForManifest(overrides []configv1.ComponentOverride, excludeIdentifier string, manifest *lib.Manifest) (configv1.ComponentOverride, bool) { for idx, ov := range overrides { kind, namespace, name := manifest.GVK.Kind, manifest.Object().GetNamespace(), manifest.Object().GetName() if ov.Kind == kind && @@ -915,6 +922,10 @@ func getOverrideForManifest(overrides []configv1.ComponentOverride, manifest *li return overrides[idx], true } } + excludeAnnotation := fmt.Sprintf("exclude.release.openshift.io/%s", excludeIdentifier) + if annotations := manifest.Object().GetAnnotations(); annotations != nil && annotations[excludeAnnotation] == "true" { + return configv1.ComponentOverride{Unmanaged: true}, true + } return configv1.ComponentOverride{}, false } diff --git a/pkg/start/start.go b/pkg/start/start.go index e28708dab4..c56436f23b 100644 --- a/pkg/start/start.go +++ b/pkg/start/start.go @@ -58,6 +58,11 @@ type Options struct { EnableAutoUpdate bool EnableDefaultClusterVersion bool + // Exclude is used to determine whether to exclude + // certain manifests based on an annotation: + // exclude.release.openshift.io/=true + Exclude string + // for testing only Name string Namespace string @@ -87,6 +92,7 @@ func NewOptions() *Options { PayloadOverride: os.Getenv("PAYLOAD_OVERRIDE"), ResyncInterval: minResyncPeriod, EnableMetrics: true, + Exclude: os.Getenv("EXCLUDE_MANIFESTS"), } } @@ -100,6 +106,9 @@ func (o *Options) Run() error { if len(o.PayloadOverride) > 0 { klog.Warningf("Using an override payload directory for testing only: %s", o.PayloadOverride) } + if len(o.Exclude) > 0 { + klog.Infof("Excluding manifests for %q", o.Exclude) + } // initialize the core objects cb, err := newClientBuilder(o.Kubeconfig) @@ -337,6 +346,7 @@ func (o *Options) NewControllerContext(cb *ClientBuilder) *Context { cb.ClientOrDie(o.Namespace), cb.KubeClientOrDie(o.Namespace, useProtobuf), o.EnableMetrics, + o.Exclude, ), } if o.EnableAutoUpdate { diff --git a/pkg/start/start_integration_test.go b/pkg/start/start_integration_test.go index a1a0b6b145..446fba9d4d 100644 --- a/pkg/start/start_integration_test.go +++ b/pkg/start/start_integration_test.go @@ -241,7 +241,7 @@ func TestIntegrationCVO_initializeAndUpgrade(t *testing.T) { options.EnableMetrics = false controllers := options.NewControllerContext(cb) - worker := cvo.NewSyncWorker(retriever, cvo.NewResourceBuilder(cfg, cfg, nil), 5*time.Second, wait.Backoff{Steps: 3}) + worker := cvo.NewSyncWorker(retriever, cvo.NewResourceBuilder(cfg, cfg, nil), 5*time.Second, wait.Backoff{Steps: 3}, "") controllers.CVO.SetSyncWorkerForTesting(worker) ctx, cancel := context.WithCancel(context.Background()) @@ -394,7 +394,7 @@ func TestIntegrationCVO_initializeAndHandleError(t *testing.T) { options.ResyncInterval = 3 * time.Second controllers := options.NewControllerContext(cb) - worker := cvo.NewSyncWorker(retriever, cvo.NewResourceBuilder(cfg, cfg, nil), 5*time.Second, wait.Backoff{Duration: time.Second, Factor: 1.2}) + worker := cvo.NewSyncWorker(retriever, cvo.NewResourceBuilder(cfg, cfg, nil), 5*time.Second, wait.Backoff{Duration: time.Second, Factor: 1.2}, "") controllers.CVO.SetSyncWorkerForTesting(worker) ctx, cancel := context.WithCancel(context.Background()) @@ -500,7 +500,7 @@ func TestIntegrationCVO_gracefulStepDown(t *testing.T) { options.EnableMetrics = false controllers := options.NewControllerContext(cb) - worker := cvo.NewSyncWorker(&mapPayloadRetriever{}, cvo.NewResourceBuilder(cfg, cfg, nil), 5*time.Second, wait.Backoff{Steps: 3}) + worker := cvo.NewSyncWorker(&mapPayloadRetriever{}, cvo.NewResourceBuilder(cfg, cfg, nil), 5*time.Second, wait.Backoff{Steps: 3}, "") controllers.CVO.SetSyncWorkerForTesting(worker) lock, err := createResourceLock(cb, ns, ns) @@ -673,7 +673,7 @@ metadata: t.Fatal(err) } - worker := cvo.NewSyncWorker(retriever, cvo.NewResourceBuilder(cfg, cfg, nil), 5*time.Second, wait.Backoff{Steps: 3}) + worker := cvo.NewSyncWorker(retriever, cvo.NewResourceBuilder(cfg, cfg, nil), 5*time.Second, wait.Backoff{Steps: 3}, "") controllers.CVO.SetSyncWorkerForTesting(worker) ctx, cancel := context.WithCancel(context.Background())