diff --git a/pkg/controller/resourcequota/replenishment_controller.go b/pkg/controller/resourcequota/replenishment_controller.go index 25a84a02e0..f5c92b2b7f 100644 --- a/pkg/controller/resourcequota/replenishment_controller.go +++ b/pkg/controller/resourcequota/replenishment_controller.go @@ -214,7 +214,7 @@ func (r *replenishmentControllerFactory) NewController(options *ReplenishmentCon }, ) default: - return nil, fmt.Errorf("no replenishment controller available for %s", options.GroupKind) + return nil, NewUnhandledGroupKindError(options.GroupKind) } return result, nil } @@ -229,3 +229,38 @@ func ServiceReplenishmentUpdateFunc(options *ReplenishmentControllerOptions) fun } } } + +type unhandledKindErr struct { + kind unversioned.GroupKind +} + +func (e unhandledKindErr) Error() string { + return fmt.Sprintf("no replenishment controller available for %s", e.kind) +} + +func NewUnhandledGroupKindError(kind unversioned.GroupKind) error { + return unhandledKindErr{kind: kind} +} + +func IsUnhandledGroupKindError(err error) bool { + if err == nil { + return false + } + _, ok := err.(unhandledKindErr) + return ok +} + +// UnionReplenishmentControllerFactory iterates through its constituent factories ignoring, UnhandledGroupKindErrors +// returning the first success or failure it hits. If there are no hits either way, it return an UnhandledGroupKind error +type UnionReplenishmentControllerFactory []ReplenishmentControllerFactory + +func (f UnionReplenishmentControllerFactory) NewController(options *ReplenishmentControllerOptions) (framework.ControllerInterface, error) { + for _, factory := range f { + controller, err := factory.NewController(options) + if !IsUnhandledGroupKindError(err) { + return controller, err + } + } + + return nil, NewUnhandledGroupKindError(options.GroupKind) +} diff --git a/pkg/quota/interfaces.go b/pkg/quota/interfaces.go index 728f8e5b83..6a8653b1af 100644 --- a/pkg/quota/interfaces.go +++ b/pkg/quota/interfaces.go @@ -64,3 +64,19 @@ type Registry interface { // Evaluators returns the set Evaluator objects registered to a groupKind Evaluators() map[unversioned.GroupKind]Evaluator } + +// UnionRegistry combines multiple registries. Order matters because first registry to claim a GroupKind +// is the "winner" +type UnionRegistry []Registry + +func (r UnionRegistry) Evaluators() map[unversioned.GroupKind]Evaluator { + ret := map[unversioned.GroupKind]Evaluator{} + + for i := len(r) - 1; i >= 0; i-- { + for k, v := range r[i].Evaluators() { + ret[k] = v + } + } + + return ret +}