Allow namespace configuration for different CRD resources in Fission (#2539)

* Allow multiple namespaces for builder manager
* Enable multiple namespaces for executor informers
* Added missing context
* helm chart support for multiple namespaces
* Directly consume map type from GetInformerForNamespaces fn
* Optimize function resolver by choosing namespace-specific informer
* helm chart support for multiple namespaces
* consider default namespace and move duplicate code to helm template
* Improve documentation for fission namespace values

Signed-off-by: Sanket Sudake <sanketsudake@gmail.com>
Co-authored-by: shubham bansal <shubhambansaliimtgn@gmail.com>
This commit is contained in:
Sanket Sudake
2022-10-19 15:48:47 +05:30
committed by GitHub
co-authored by shubham bansal
parent facd14de90
commit 827baea974
27 changed files with 430 additions and 219 deletions
+30 -8
View File
@@ -21,6 +21,7 @@ import (
"time"
"github.com/pkg/errors"
"go.uber.org/zap"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
k8sCache "k8s.io/client-go/tools/cache"
@@ -34,7 +35,8 @@ type (
functionReferenceResolver struct {
// FunctionReference -> function metadata
refCache *cache.Cache
funcInformer *k8sCache.SharedIndexInformer
funcInformer map[string]k8sCache.SharedIndexInformer
logger *zap.Logger
// store k8sCache.Store
}
@@ -69,10 +71,11 @@ const (
resolveResultMultipleFunctions
)
func makeFunctionReferenceResolver(funcInformer *k8sCache.SharedIndexInformer) *functionReferenceResolver {
func makeFunctionReferenceResolver(logger *zap.Logger, funcInformer map[string]k8sCache.SharedIndexInformer) *functionReferenceResolver {
frr := &functionReferenceResolver{
refCache: cache.MakeCache(time.Minute, 0),
funcInformer: funcInformer,
logger: logger.Named("function_ref_resolver"),
}
return frr
}
@@ -118,10 +121,24 @@ func (frr *functionReferenceResolver) resolve(trigger fv1.HTTPTrigger) (*resolve
return rr, nil
}
func (frr *functionReferenceResolver) getInformerByNamespace(namespace string) (k8sCache.SharedIndexInformer, error) {
if informer, ok := frr.funcInformer[metav1.NamespaceAll]; ok {
return informer, nil
}
if informer, ok := frr.funcInformer[namespace]; ok {
return informer, nil
}
return nil, fmt.Errorf("informer for namespace %s not found", namespace)
}
// resolveByName simply looks up function by name in a namespace.
func (frr *functionReferenceResolver) resolveByName(namespace, name string) (*resolveResult, error) {
// get function from cache
obj, isExist, err := (*frr.funcInformer).GetStore().Get(&fv1.Function{
informer, err := frr.getInformerByNamespace(namespace)
if err != nil {
return nil, err
}
obj, isExist, err := informer.GetStore().Get(&fv1.Function{
ObjectMeta: metav1.ObjectMeta{
Namespace: namespace,
Name: name,
@@ -131,10 +148,11 @@ func (frr *functionReferenceResolver) resolveByName(namespace, name string) (*re
return nil, err
}
if !isExist {
return nil, errors.Errorf("function %v does not exist", name)
frr.logger.Error("function does not exists", zap.String("name", name), zap.String("namespace", namespace))
return nil, errors.Errorf("function %s/%s does not exist", namespace, name)
}
f := obj.(*fv1.Function)
functionMap := map[string]*fv1.Function{
f.ObjectMeta.Name: f,
}
@@ -155,7 +173,11 @@ func (frr *functionReferenceResolver) resolveByFunctionWeights(namespace string,
for functionName, functionWeight := range fr.FunctionWeights {
// get function from cache
obj, isExist, err := (*frr.funcInformer).GetStore().Get(&fv1.Function{
informer, err := frr.getInformerByNamespace(namespace)
if err != nil {
return nil, err
}
obj, isExist, err := informer.GetStore().Get(&fv1.Function{
ObjectMeta: metav1.ObjectMeta{
Namespace: namespace,
Name: functionName,
@@ -165,9 +187,9 @@ func (frr *functionReferenceResolver) resolveByFunctionWeights(namespace string,
return nil, err
}
if !isExist {
return nil, fmt.Errorf("function %v does not exist", functionName)
frr.logger.Error("function does not exists", zap.String("name", functionName), zap.String("namespace", namespace))
return nil, fmt.Errorf("function %s/%s does not exist", namespace, functionName)
}
f := obj.(*fv1.Function)
functionMap[f.ObjectMeta.Name] = f
sumPrefix = sumPrefix + functionWeight
+81 -76
View File
@@ -32,7 +32,6 @@ import (
executorClient "github.com/fission/fission/pkg/executor/client"
config "github.com/fission/fission/pkg/featureconfig"
"github.com/fission/fission/pkg/generated/clientset/versioned"
genInformer "github.com/fission/fission/pkg/generated/informers/externalversions"
"github.com/fission/fission/pkg/throttler"
"github.com/fission/fission/pkg/utils"
"github.com/fission/fission/pkg/utils/metrics"
@@ -50,9 +49,9 @@ type HTTPTriggerSet struct {
executor *executorClient.Client
resolver *functionReferenceResolver
triggers []fv1.HTTPTrigger
triggerInformer k8sCache.SharedIndexInformer
triggerInformer map[string]k8sCache.SharedIndexInformer
functions []fv1.Function
funcInformer k8sCache.SharedIndexInformer
funcInformer map[string]k8sCache.SharedIndexInformer
updateRouterRequestChannel chan struct{}
tsRoundTripperParams *tsRoundTripperParams
isDebugEnv bool
@@ -76,18 +75,15 @@ func makeHTTPTriggerSet(logger *zap.Logger, fmap *functionServiceMap, fissionCli
svcAddrUpdateThrottler: actionThrottler,
unTapServiceTimeout: unTapServiceTimeout,
}
informerFactory := genInformer.NewSharedInformerFactory(fissionClient, time.Minute*30)
httpTriggerSet.triggerInformer = informerFactory.Core().V1().HTTPTriggers().Informer()
httpTriggerSet.funcInformer = informerFactory.Core().V1().Functions().Informer()
httpTriggerSet.triggerInformer = utils.GetInformersForNamespaces(fissionClient, time.Minute*30, fv1.HttpTriggerResource)
httpTriggerSet.funcInformer = utils.GetInformersForNamespaces(fissionClient, time.Minute*30, fv1.FunctionResource)
httpTriggerSet.addTriggerHandlers()
httpTriggerSet.addFunctionHandlers()
return httpTriggerSet
}
func (ts *HTTPTriggerSet) subscribeRouter(ctx context.Context, mr *mutableRouter) {
resolver := makeFunctionReferenceResolver(&ts.funcInformer)
resolver := makeFunctionReferenceResolver(ts.logger, ts.funcInformer)
ts.resolver = resolver
ts.mutableRouter = mr
@@ -280,70 +276,75 @@ func (ts *HTTPTriggerSet) updateTriggerStatusFailed(ht *fv1.HTTPTrigger, err err
}
func (ts *HTTPTriggerSet) addTriggerHandlers() {
ts.triggerInformer.AddEventHandler(k8sCache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
trigger := obj.(*fv1.HTTPTrigger)
go createIngress(context.Background(), ts.logger, trigger, ts.kubeClient)
ts.syncTriggers()
},
DeleteFunc: func(obj interface{}) {
ts.syncTriggers()
trigger := obj.(*fv1.HTTPTrigger)
go deleteIngress(context.Background(), ts.logger, trigger, ts.kubeClient)
},
UpdateFunc: func(oldObj interface{}, newObj interface{}) {
oldTrigger := oldObj.(*fv1.HTTPTrigger)
newTrigger := newObj.(*fv1.HTTPTrigger)
for _, triggerInformer := range ts.triggerInformer {
triggerInformer.AddEventHandler(k8sCache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
trigger := obj.(*fv1.HTTPTrigger)
go createIngress(context.Background(), ts.logger, trigger, ts.kubeClient)
ts.syncTriggers()
},
DeleteFunc: func(obj interface{}) {
ts.syncTriggers()
trigger := obj.(*fv1.HTTPTrigger)
go deleteIngress(context.Background(), ts.logger, trigger, ts.kubeClient)
},
UpdateFunc: func(oldObj interface{}, newObj interface{}) {
oldTrigger := oldObj.(*fv1.HTTPTrigger)
newTrigger := newObj.(*fv1.HTTPTrigger)
if oldTrigger.ObjectMeta.ResourceVersion == newTrigger.ObjectMeta.ResourceVersion {
return
}
if oldTrigger.ObjectMeta.ResourceVersion == newTrigger.ObjectMeta.ResourceVersion {
return
}
go updateIngress(context.Background(), ts.logger, oldTrigger, newTrigger, ts.kubeClient)
ts.syncTriggers()
},
})
go updateIngress(context.Background(), ts.logger, oldTrigger, newTrigger, ts.kubeClient)
ts.syncTriggers()
},
})
}
}
func (ts *HTTPTriggerSet) addFunctionHandlers() {
ts.funcInformer.AddEventHandler(k8sCache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
ts.syncTriggers()
},
DeleteFunc: func(obj interface{}) {
ts.syncTriggers()
},
UpdateFunc: func(oldObj interface{}, newObj interface{}) {
oldFn := oldObj.(*fv1.Function)
fn := newObj.(*fv1.Function)
for _, funcInformer := range ts.funcInformer {
if oldFn.ObjectMeta.ResourceVersion == fn.ObjectMeta.ResourceVersion {
return
}
funcInformer.AddEventHandler(k8sCache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
ts.syncTriggers()
},
DeleteFunc: func(obj interface{}) {
ts.syncTriggers()
},
UpdateFunc: func(oldObj interface{}, newObj interface{}) {
oldFn := oldObj.(*fv1.Function)
fn := newObj.(*fv1.Function)
// update resolver function reference cache
for key, rr := range ts.resolver.copy() {
if key.namespace == fn.ObjectMeta.Namespace &&
rr.functionMap[fn.ObjectMeta.Name] != nil &&
rr.functionMap[fn.ObjectMeta.Name].ObjectMeta.ResourceVersion != fn.ObjectMeta.ResourceVersion {
// invalidate resolver cache
ts.logger.Debug("invalidating resolver cache")
err := ts.resolver.delete(key.namespace, key.triggerName, key.triggerResourceVersion)
if err != nil {
ts.logger.Error("error deleting functionReferenceResolver cache", zap.Error(err))
}
break
if oldFn.ObjectMeta.ResourceVersion == fn.ObjectMeta.ResourceVersion {
return
}
}
ts.syncTriggers()
},
})
// update resolver function reference cache
for key, rr := range ts.resolver.copy() {
if key.namespace == fn.ObjectMeta.Namespace &&
rr.functionMap[fn.ObjectMeta.Name] != nil &&
rr.functionMap[fn.ObjectMeta.Name].ObjectMeta.ResourceVersion != fn.ObjectMeta.ResourceVersion {
// invalidate resolver cache
ts.logger.Debug("invalidating resolver cache")
err := ts.resolver.delete(key.namespace, key.triggerName, key.triggerResourceVersion)
if err != nil {
ts.logger.Error("error deleting functionReferenceResolver cache", zap.Error(err))
}
break
}
}
ts.syncTriggers()
},
})
}
}
func (ts *HTTPTriggerSet) runInformer(ctx context.Context, informer k8sCache.SharedIndexInformer) {
go func() {
informer.Run(ctx.Done())
}()
func (ts *HTTPTriggerSet) runInformer(ctx context.Context, informer map[string]k8sCache.SharedIndexInformer) {
for _, inf := range informer {
go inf.Run(ctx.Done())
}
}
func (ts *HTTPTriggerSet) syncTriggers() {
@@ -353,23 +354,27 @@ func (ts *HTTPTriggerSet) syncTriggers() {
func (ts *HTTPTriggerSet) updateRouter() {
for range ts.updateRouterRequestChannel {
// get triggers
latestTriggers := ts.triggerInformer.GetStore().List()
triggers := make([]fv1.HTTPTrigger, len(latestTriggers))
for _, t := range latestTriggers {
triggers = append(triggers, *t.(*fv1.HTTPTrigger))
alltriggers := make([]fv1.HTTPTrigger, 0)
for _, triggerInformer := range ts.triggerInformer {
latestTriggers := triggerInformer.GetStore().List()
for _, t := range latestTriggers {
alltriggers = append(alltriggers, *t.(*fv1.HTTPTrigger))
}
}
ts.triggers = triggers
ts.triggers = alltriggers
// get functions
latestFunctions := ts.funcInformer.GetStore().List()
functionTimeout := make(map[types.UID]int, len(latestFunctions))
functions := make([]fv1.Function, len(latestFunctions))
for _, f := range latestFunctions {
fn := *f.(*fv1.Function)
functionTimeout[fn.ObjectMeta.UID] = fn.Spec.FunctionTimeout
functions = append(functions, *f.(*fv1.Function))
allfunctions := make([]fv1.Function, 0)
functionTimeout := make(map[types.UID]int, 0)
for _, funcInformer := range ts.funcInformer {
latestFunctions := funcInformer.GetStore().List()
for _, f := range latestFunctions {
fn := *f.(*fv1.Function)
functionTimeout[fn.ObjectMeta.UID] = fn.Spec.FunctionTimeout
allfunctions = append(allfunctions, fn)
}
}
ts.functions = functions
ts.functions = allfunctions
// make a new router and use it
ts.mutableRouter.updateRouter(ts.getRouter(functionTimeout))