211 lines
5.6 KiB
Go
211 lines
5.6 KiB
Go
package utils
|
|
|
|
import (
|
|
"os"
|
|
"sort"
|
|
"strings"
|
|
"sync"
|
|
|
|
"go.uber.org/zap"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
|
|
"github.com/fission/fission/pkg/utils/loggerfactory"
|
|
)
|
|
|
|
const (
|
|
ENV_FUNCTION_NAMESPACE string = "FISSION_FUNCTION_NAMESPACE"
|
|
ENV_BUILDER_NAMESPACE string = "FISSION_BUILDER_NAMESPACE"
|
|
ENV_DEFAULT_NAMESPACE string = "FISSION_DEFAULT_NAMESPACE"
|
|
ENV_ADDITIONAL_NAMESPACE string = "FISSION_RESOURCE_NAMESPACES"
|
|
)
|
|
|
|
type (
|
|
NamespaceResolver struct {
|
|
mu sync.RWMutex // protects FissionResourceNS
|
|
|
|
FunctionNamespace string
|
|
BuilderNamespace string
|
|
DefaultNamespace string
|
|
FissionResourceNS map[string]string
|
|
Logger *zap.Logger
|
|
}
|
|
|
|
options struct {
|
|
functionNS bool
|
|
builderNS bool
|
|
defaultNs bool
|
|
}
|
|
|
|
option func(options *options) *options
|
|
)
|
|
|
|
var nsResolver *NamespaceResolver
|
|
|
|
func init() {
|
|
nsResolver = &NamespaceResolver{
|
|
FunctionNamespace: os.Getenv(ENV_FUNCTION_NAMESPACE),
|
|
BuilderNamespace: os.Getenv(ENV_BUILDER_NAMESPACE),
|
|
DefaultNamespace: os.Getenv(ENV_DEFAULT_NAMESPACE),
|
|
FissionResourceNS: GetNamespaces(),
|
|
Logger: loggerfactory.GetLogger(),
|
|
}
|
|
|
|
nsResolver.Logger.Debug("namespaces", zap.String("function_namespace", nsResolver.FunctionNamespace),
|
|
zap.String("builder_namespace", nsResolver.BuilderNamespace),
|
|
zap.String("default_namespace", nsResolver.DefaultNamespace),
|
|
zap.Any("fission_resource_namespace", listNamespaces(nsResolver.FissionResourceNS)))
|
|
}
|
|
|
|
// listNamespaces => convert namespaces from map to slice
|
|
func listNamespaces(namespaces map[string]string) []string {
|
|
ns := make([]string, 0)
|
|
for _, namespace := range namespaces {
|
|
ns = append(ns, namespace)
|
|
}
|
|
return ns
|
|
}
|
|
|
|
func WithBuilderNs() option {
|
|
return func(options *options) *options {
|
|
options.builderNS = true
|
|
return options
|
|
}
|
|
}
|
|
|
|
func WithFunctionNs() option {
|
|
return func(options *options) *options {
|
|
options.functionNS = true
|
|
return options
|
|
}
|
|
}
|
|
|
|
func WithDefaultNs() option {
|
|
return func(options *options) *options {
|
|
options.defaultNs = true
|
|
return options
|
|
}
|
|
}
|
|
|
|
// AddNamespace dynamically adds a namespace to FissionResourceNS without restarting the process.
|
|
// Returns true if the namespace was newly added, false if it was already present.
|
|
// Thread-safe — multiple goroutines may call this concurrently.
|
|
// The label fission.io/managed=true on the Namespace object is the trigger for this call.
|
|
func (nsr *NamespaceResolver) AddNamespace(ns string) bool {
|
|
nsr.mu.Lock()
|
|
defer nsr.mu.Unlock()
|
|
if _, exists := nsr.FissionResourceNS[ns]; exists {
|
|
return false
|
|
}
|
|
nsr.FissionResourceNS[ns] = ns
|
|
if nsr.Logger != nil {
|
|
nsr.Logger.Info("dynamically added namespace to resolver", zap.String("namespace", ns))
|
|
}
|
|
return true
|
|
}
|
|
|
|
// Snapshot returns a stable copy of the currently registered resource namespaces.
|
|
// The returned slice is detached from the internal mutable map and safe to iterate.
|
|
func (nsr *NamespaceResolver) Snapshot() []string {
|
|
nsr.mu.RLock()
|
|
defer nsr.mu.RUnlock()
|
|
|
|
namespaces := listNamespaces(nsr.FissionResourceNS)
|
|
sort.Strings(namespaces)
|
|
return namespaces
|
|
}
|
|
|
|
func (nsr *NamespaceResolver) FissionNSWithOptions(option ...option) map[string]string {
|
|
var options options
|
|
for _, opt := range option {
|
|
options = *opt(&options)
|
|
}
|
|
|
|
nsr.mu.RLock()
|
|
fissionResourceNS := make(map[string]string, len(nsr.FissionResourceNS))
|
|
for k, v := range nsr.FissionResourceNS {
|
|
fissionResourceNS[k] = v
|
|
}
|
|
nsr.mu.RUnlock()
|
|
|
|
if options.functionNS && nsr.FunctionNamespace != "" {
|
|
fissionResourceNS[nsr.FunctionNamespace] = nsr.FunctionNamespace
|
|
}
|
|
if options.builderNS && nsr.BuilderNamespace != "" {
|
|
fissionResourceNS[nsr.BuilderNamespace] = nsr.BuilderNamespace
|
|
}
|
|
if options.defaultNs && nsr.DefaultNamespace != "" {
|
|
fissionResourceNS[nsr.DefaultNamespace] = nsr.DefaultNamespace
|
|
}
|
|
if nsr.Logger != nil {
|
|
nsr.Logger.Debug("fission resource namespaces", zap.Any("namespaces", listNamespaces(fissionResourceNS)))
|
|
}
|
|
return fissionResourceNS
|
|
}
|
|
|
|
// SnapshotWithOptions returns a stable slice copy of Fission namespaces after applying
|
|
// optional builder/function/default namespace expansion.
|
|
func (nsr *NamespaceResolver) SnapshotWithOptions(option ...option) []string {
|
|
namespaces := listNamespaces(nsr.FissionNSWithOptions(option...))
|
|
sort.Strings(namespaces)
|
|
return namespaces
|
|
}
|
|
|
|
func GetNamespaces() map[string]string {
|
|
namespaces := make(map[string]string)
|
|
|
|
envValue := os.Getenv(ENV_DEFAULT_NAMESPACE)
|
|
if len(envValue) > 0 {
|
|
namespaces[envValue] = envValue
|
|
}
|
|
|
|
envValue = os.Getenv(ENV_ADDITIONAL_NAMESPACE)
|
|
if len(envValue) > 0 {
|
|
lstNamespaces := strings.Split(envValue, ",")
|
|
for _, namespace := range lstNamespaces {
|
|
// check to handle string with additional comma at the end of string. eg- ns1,ns2,
|
|
if namespace != "" {
|
|
namespaces[namespace] = namespace
|
|
}
|
|
}
|
|
}
|
|
|
|
if len(namespaces) == 0 {
|
|
namespaces[metav1.NamespaceDefault] = metav1.NamespaceDefault
|
|
}
|
|
return namespaces
|
|
}
|
|
|
|
func (nsr *NamespaceResolver) GetBuilderNS(namespace string) string {
|
|
if nsr.BuilderNamespace == "" {
|
|
return namespace
|
|
}
|
|
|
|
if namespace != metav1.NamespaceDefault {
|
|
return namespace
|
|
}
|
|
return nsr.BuilderNamespace
|
|
}
|
|
|
|
func (nsr *NamespaceResolver) GetFunctionNS(namespace string) string {
|
|
if nsr.FunctionNamespace == "" {
|
|
return namespace
|
|
}
|
|
|
|
if namespace != metav1.NamespaceDefault {
|
|
return namespace
|
|
}
|
|
return nsr.FunctionNamespace
|
|
}
|
|
|
|
func (nsr *NamespaceResolver) ResolveNamespace(namespace string) string {
|
|
if nsr.FunctionNamespace == "" || nsr.BuilderNamespace == "" {
|
|
return nsr.DefaultNamespace
|
|
}
|
|
return namespace
|
|
}
|
|
|
|
// GetFissionNamespaces => return all fission core component namespaces
|
|
func DefaultNSResolver() *NamespaceResolver {
|
|
return nsResolver
|
|
}
|