105 lines
3.1 KiB
Go
105 lines
3.1 KiB
Go
/*
|
|
Copyright 2015 Google Inc. All rights reserved.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package framework
|
|
|
|
import (
|
|
"time"
|
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/client/cache"
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
|
)
|
|
|
|
// Config contains all the settings for a Controller.
|
|
type Config struct {
|
|
// The queue for your objects; either a cache.FIFO or
|
|
// a cache.DeltaFIFO. Your Process() function should accept
|
|
// the output of this Oueue's Pop() method.
|
|
cache.Queue
|
|
|
|
// Something that can list and watch your objects.
|
|
cache.ListerWatcher
|
|
|
|
// Something that can process your objects.
|
|
Process ProcessFunc
|
|
|
|
// The type of your objects.
|
|
ObjectType runtime.Object
|
|
|
|
// Reprocess everything at least this often.
|
|
// Note that if it takes longer for you to clear the queue than this
|
|
// period, you will end up processing items in the order determined
|
|
// by cache.FIFO.Replace(). Currently, this is random. If this is a
|
|
// problem, we can change that replacement policy to append new
|
|
// things to the end of the queue instead of replacing the entire
|
|
// queue.
|
|
FullResyncPeriod time.Duration
|
|
|
|
// If true, when Process() returns an error, re-enqueue the object.
|
|
// TODO: add interface to let you inject a delay/backoff or drop
|
|
// the object completely if desired. Pass the object in
|
|
// question to this interface as a parameter.
|
|
RetryOnError bool
|
|
}
|
|
|
|
// ProcessFunc processes a single object.
|
|
type ProcessFunc func(obj interface{}) error
|
|
|
|
// Controller is a generic controller framework.
|
|
type Controller struct {
|
|
config Config
|
|
}
|
|
|
|
// New makes a new Controller from the given Config.
|
|
func New(c *Config) *Controller {
|
|
ctlr := &Controller{
|
|
config: *c,
|
|
}
|
|
return ctlr
|
|
}
|
|
|
|
// Run begins processing items, and will continue until a value is sent down stopCh.
|
|
// It's an error to call Run more than once.
|
|
// Run does not block.
|
|
func (c *Controller) Run(stopCh <-chan struct{}) {
|
|
cache.NewReflector(
|
|
c.config.ListerWatcher,
|
|
c.config.ObjectType,
|
|
c.config.Queue,
|
|
c.config.FullResyncPeriod,
|
|
).RunUntil(stopCh)
|
|
|
|
go util.Until(c.processLoop, time.Second, stopCh)
|
|
}
|
|
|
|
// processLoop drains the work queue.
|
|
// TODO: Consider doing the processing in parallel. This will require a little thought
|
|
// to make sure that we don't end up processing the same object multiple times
|
|
// concurrently.
|
|
func (c *Controller) processLoop() {
|
|
for {
|
|
obj := c.config.Queue.Pop()
|
|
err := c.config.Process(obj)
|
|
if err != nil {
|
|
if c.config.RetryOnError {
|
|
// This is the safe way to re-enqueue.
|
|
c.config.Queue.AddIfNotPresent(obj)
|
|
}
|
|
}
|
|
}
|
|
}
|