Test for httptrigger and functions container/newdeploy (#2861)
* Test for httptrigger and functions * Fixes with multierror * review changes Signed-off-by: Sanket Sudake <sanketsudake@gmail.com>
This commit is contained in:
@@ -18,11 +18,10 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
multierror "github.com/hashicorp/go-multierror"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||||
apiextensionsclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
|
apiextensionsclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
|
||||||
@@ -52,17 +51,18 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func makePreUpgradeTaskClient(clientGen crd.ClientGeneratorInterface, logger *zap.Logger) (*PreUpgradeTaskClient, error) {
|
func makePreUpgradeTaskClient(clientGen crd.ClientGeneratorInterface, logger *zap.Logger) (*PreUpgradeTaskClient, error) {
|
||||||
|
var err error
|
||||||
fissionClient, err := clientGen.GetFissionClient()
|
fissionClient, err := clientGen.GetFissionClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "failed to get fission client")
|
return nil, fmt.Errorf("failed to get fission client: %w", err)
|
||||||
}
|
}
|
||||||
k8sClient, err := clientGen.GetKubernetesClient()
|
k8sClient, err := clientGen.GetKubernetesClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "failed to get kubernetes client")
|
return nil, fmt.Errorf("failed to get kubernetes client: %w", err)
|
||||||
}
|
}
|
||||||
apiExtClient, err := clientGen.GetApiExtensionsClient()
|
apiExtClient, err := clientGen.GetApiExtensionsClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "failed to get apiextensions client")
|
return nil, fmt.Errorf("failed to get apiextensions client: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &PreUpgradeTaskClient{
|
return &PreUpgradeTaskClient{
|
||||||
@@ -129,7 +129,7 @@ func (client *PreUpgradeTaskClient) VerifyFunctionSpecReferences(ctx context.Con
|
|||||||
|
|
||||||
var err error
|
var err error
|
||||||
var fList *fv1.FunctionList
|
var fList *fv1.FunctionList
|
||||||
errs := &multierror.Error{}
|
var errs error
|
||||||
|
|
||||||
for _, namespace := range utils.DefaultNSResolver().FissionResourceNS {
|
for _, namespace := range utils.DefaultNSResolver().FissionResourceNS {
|
||||||
for i := 0; i < maxRetries; i++ {
|
for i := 0; i < maxRetries; i++ {
|
||||||
@@ -150,24 +150,25 @@ func (client *PreUpgradeTaskClient) VerifyFunctionSpecReferences(ctx context.Con
|
|||||||
secrets := fn.Spec.Secrets
|
secrets := fn.Spec.Secrets
|
||||||
for _, secret := range secrets {
|
for _, secret := range secrets {
|
||||||
if secret.Namespace != "" && secret.Namespace != fn.ObjectMeta.Namespace {
|
if secret.Namespace != "" && secret.Namespace != fn.ObjectMeta.Namespace {
|
||||||
errs = multierror.Append(errs, fmt.Errorf("function : %s.%s cannot reference a secret : %s in namespace : %s", fn.ObjectMeta.Name, fn.ObjectMeta.Namespace, secret.Name, secret.Namespace))
|
errs = errors.Join(errs, fmt.Errorf("function : %s.%s cannot reference a secret : %s in namespace : %s", fn.ObjectMeta.Name, fn.ObjectMeta.Namespace, secret.Name, secret.Namespace))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
configmaps := fn.Spec.ConfigMaps
|
configmaps := fn.Spec.ConfigMaps
|
||||||
for _, configmap := range configmaps {
|
for _, configmap := range configmaps {
|
||||||
if configmap.Namespace != "" && configmap.Namespace != fn.ObjectMeta.Namespace {
|
if configmap.Namespace != "" && configmap.Namespace != fn.ObjectMeta.Namespace {
|
||||||
errs = multierror.Append(errs, fmt.Errorf("function : %s.%s cannot reference a configmap : %s in namespace : %s", fn.ObjectMeta.Name, fn.ObjectMeta.Namespace, configmap.Name, configmap.Namespace))
|
errs = errors.Join(errs, fmt.Errorf("function : %s.%s cannot reference a configmap : %s in namespace : %s", fn.ObjectMeta.Name, fn.ObjectMeta.Namespace, configmap.Name, configmap.Namespace))
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if fn.Spec.Package.PackageRef.Namespace != "" && fn.Spec.Package.PackageRef.Namespace != fn.ObjectMeta.Namespace {
|
if fn.Spec.Package.PackageRef.Namespace != "" && fn.Spec.Package.PackageRef.Namespace != fn.ObjectMeta.Namespace {
|
||||||
errs = multierror.Append(errs, fmt.Errorf("function : %s.%s cannot reference a package : %s in namespace : %s", fn.ObjectMeta.Name, fn.ObjectMeta.Namespace, fn.Spec.Package.PackageRef.Name, fn.Spec.Package.PackageRef.Namespace))
|
errs = errors.Join(errs, fmt.Errorf("function : %s.%s cannot reference a package : %s in namespace : %s", fn.ObjectMeta.Name, fn.ObjectMeta.Namespace, fn.Spec.Package.PackageRef.Name, fn.Spec.Package.PackageRef.Namespace))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if errs.ErrorOrNil() != nil {
|
if errs != nil {
|
||||||
client.logger.Fatal("installation failed",
|
client.logger.Fatal("installation failed",
|
||||||
zap.Error(errs),
|
zap.Error(errs),
|
||||||
zap.String("summary", "a function cannot reference secrets, configmaps and packages outside it's own namespace"))
|
zap.String("summary", "a function cannot reference secrets, configmaps and packages outside it's own namespace"))
|
||||||
|
|||||||
@@ -129,25 +129,24 @@ func ValidateKubeLabel(field string, labels map[string]string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ValidateKubePort(field string, port int) error {
|
func ValidateKubePort(field string, port int) error {
|
||||||
result := &multierror.Error{}
|
var err error
|
||||||
|
|
||||||
e := validation.IsValidPortNum(port)
|
e := validation.IsValidPortNum(port)
|
||||||
if len(e) > 0 {
|
if len(e) > 0 {
|
||||||
result = multierror.Append(result, MakeValidationErr(ErrorInvalidValue, field, port, e...))
|
err = errors.Join(err, MakeValidationErr(ErrorInvalidValue, field, port, e...))
|
||||||
}
|
}
|
||||||
|
return err
|
||||||
return result.ErrorOrNil()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func ValidateKubeName(field string, val string) error {
|
func ValidateKubeName(field string, val string) error {
|
||||||
result := &multierror.Error{}
|
var err error
|
||||||
|
|
||||||
e := validation.IsDNS1123Label(val)
|
e := validation.IsDNS1123Label(val)
|
||||||
if len(e) > 0 {
|
if len(e) > 0 {
|
||||||
result = multierror.Append(result, MakeValidationErr(ErrorInvalidValue, field, val, e...))
|
err = errors.Join(err, MakeValidationErr(ErrorInvalidValue, field, val, e...))
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.ErrorOrNil()
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// validateNS is to match the k8s behaviour. Where it is not mandatory to provide a NS. And so we validate it if user has provided one.
|
// validateNS is to match the k8s behaviour. Where it is not mandatory to provide a NS. And so we validate it if user has provided one.
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package buildermgr
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@@ -54,7 +55,7 @@ func Start(ctx context.Context, clientGen crd.ClientGeneratorInterface, logger *
|
|||||||
}
|
}
|
||||||
|
|
||||||
podSpecPatch, err := util.GetSpecFromConfigMap(fv1.BuilderPodSpecPath)
|
podSpecPatch, err := util.GetSpecFromConfigMap(fv1.BuilderPodSpecPath)
|
||||||
if err != nil {
|
if err != nil && !os.IsNotExist(err) {
|
||||||
logger.Warn("error reading data for pod spec patch", zap.String("path", fv1.BuilderPodSpecPath), zap.Error(err))
|
logger.Warn("error reading data for pod spec patch", zap.String("path", fv1.BuilderPodSpecPath), zap.Error(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ func ConfigureFeatures(ctx context.Context, logger *zap.Logger, unitTestMode boo
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get the featureConfig from config map mounted onto the file system
|
// get the featureConfig from config map mounted onto the file system
|
||||||
featureConfig, err := config.GetFeatureConfig()
|
featureConfig, err := config.GetFeatureConfig(logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("error getting feature config", zap.Error(err))
|
logger.Error("error getting feature config", zap.Error(err))
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -62,6 +62,13 @@ func CacheKeyURFromMeta(metadata *metav1.ObjectMeta) CacheKeyUR {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CacheKeyURFromObject(obj metav1.Object) CacheKeyUR {
|
||||||
|
return CacheKeyUR{
|
||||||
|
UID: obj.GetUID(),
|
||||||
|
ResourceVersion: obj.GetResourceVersion(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// CacheKeyURGFromMeta : Given metadata, create a key that uniquely identifies the contents
|
// CacheKeyURGFromMeta : Given metadata, create a key that uniquely identifies the contents
|
||||||
// of the object. Since resourceVersion changes on every update and
|
// of the object. Since resourceVersion changes on every update and
|
||||||
// UIDs are unique, uid+resourceVersion identifies the
|
// UIDs are unique, uid+resourceVersion identifies the
|
||||||
|
|||||||
+8
-10
@@ -19,6 +19,7 @@ package executor
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"html"
|
"html"
|
||||||
"io"
|
"io"
|
||||||
@@ -26,8 +27,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/hashicorp/go-multierror"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
|
||||||
fv1 "github.com/fission/fission/pkg/apis/core/v1"
|
fv1 "github.com/fission/fission/pkg/apis/core/v1"
|
||||||
@@ -201,27 +200,26 @@ func (executor *Executor) tapServices(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
errs := &multierror.Error{}
|
var errs error
|
||||||
for _, req := range tapSvcReqs {
|
for _, req := range tapSvcReqs {
|
||||||
svcHost := strings.TrimPrefix(req.ServiceURL, "http://")
|
svcHost := strings.TrimPrefix(req.ServiceURL, "http://")
|
||||||
|
|
||||||
et, exists := executor.executorTypes[req.FnExecutorType]
|
et, exists := executor.executorTypes[req.FnExecutorType]
|
||||||
if !exists {
|
if !exists {
|
||||||
errs = multierror.Append(errs,
|
errs = errors.Join(errs,
|
||||||
errors.Errorf("error tapping service due to unknown executor type '%v' found",
|
fmt.Errorf("error tapping service due to unknown executor type '%s' found",
|
||||||
req.FnExecutorType))
|
req.FnExecutorType))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
err = et.TapService(ctx, svcHost)
|
err = et.TapService(ctx, svcHost)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs = multierror.Append(errs,
|
errs = errors.Join(errs,
|
||||||
errors.Wrapf(err, "'%v' failed to tap function '%v' in '%v' with service url '%v'",
|
fmt.Errorf("error tapping function '%s/%s' with executor '%s' and service url '%s': %w", req.FnMetadata.Namespace, req.FnMetadata.Name, req.FnExecutorType, req.ServiceURL, err))
|
||||||
req.FnMetadata.Name, req.FnMetadata.Namespace, req.ServiceURL, req.FnExecutorType))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if errs.ErrorOrNil() != nil {
|
if errs != nil {
|
||||||
logger.Error("error tapping function service", zap.Error(errs))
|
logger.Error("error tapping function service", zap.Error(errs))
|
||||||
http.Error(w, "Not found", http.StatusNotFound)
|
http.Error(w, "Not found", http.StatusNotFound)
|
||||||
return
|
return
|
||||||
@@ -249,7 +247,7 @@ func (executor *Executor) unTapService(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
t := tapSvcReq.FnExecutorType
|
t := tapSvcReq.FnExecutorType
|
||||||
if t != fv1.ExecutorTypePoolmgr {
|
if t != fv1.ExecutorTypePoolmgr {
|
||||||
msg := fmt.Sprintf("Unknown executor type '%v'", t)
|
msg := fmt.Sprintf("Unknown executor type '%s'", t)
|
||||||
http.Error(w, html.EscapeString(msg), http.StatusBadRequest)
|
http.Error(w, html.EscapeString(msg), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ func refreshPods(ctx context.Context, logger *zap.Logger, funcs []fv1.Function,
|
|||||||
if exists {
|
if exists {
|
||||||
err = et.RefreshFuncPods(ctx, logger, f)
|
err = et.RefreshFuncPods(ctx, logger, f)
|
||||||
} else {
|
} else {
|
||||||
err = errors.Errorf("Unknown executor type '%v'", f.Spec.InvokeStrategy.ExecutionStrategy.ExecutorType)
|
err = errors.Errorf("Unknown executor type '%s'", f.Spec.InvokeStrategy.ExecutionStrategy.ExecutorType)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
+12
-10
@@ -110,7 +110,9 @@ func MakeExecutor(ctx context.Context, logger *zap.Logger, cms *cms.ConfigSecret
|
|||||||
func (executor *Executor) serveCreateFuncServices() {
|
func (executor *Executor) serveCreateFuncServices() {
|
||||||
for {
|
for {
|
||||||
req := <-executor.requestChan
|
req := <-executor.requestChan
|
||||||
fnMetadata := &req.function.ObjectMeta
|
function := req.function
|
||||||
|
fnName := k8sCache.MetaObjectToName(function)
|
||||||
|
fnkeyUR := crd.CacheKeyURFromObject(function)
|
||||||
|
|
||||||
if req.function.Spec.InvokeStrategy.ExecutionStrategy.ExecutorType == fv1.ExecutorTypePoolmgr {
|
if req.function.Spec.InvokeStrategy.ExecutionStrategy.ExecutorType == fv1.ExecutorTypePoolmgr {
|
||||||
go func() {
|
go func() {
|
||||||
@@ -138,13 +140,13 @@ func (executor *Executor) serveCreateFuncServices() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Cache miss -- is this first one to request the func?
|
// Cache miss -- is this first one to request the func?
|
||||||
wg, found := executor.fsCreateWg.Load(crd.CacheKeyURFromMeta(fnMetadata))
|
wg, found := executor.fsCreateWg.Load(fnkeyUR)
|
||||||
if !found {
|
if !found {
|
||||||
// create a waitgroup for other requests for
|
// create a waitgroup for other requests for
|
||||||
// the same function to wait on
|
// the same function to wait on
|
||||||
wg := &sync.WaitGroup{}
|
wg := &sync.WaitGroup{}
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
executor.fsCreateWg.Store(crd.CacheKeyURFromMeta(fnMetadata), wg)
|
executor.fsCreateWg.Store(fnkeyUR, wg)
|
||||||
|
|
||||||
// launch a goroutine for each request, to parallelize
|
// launch a goroutine for each request, to parallelize
|
||||||
// the specialization of different functions
|
// the specialization of different functions
|
||||||
@@ -176,17 +178,17 @@ func (executor *Executor) serveCreateFuncServices() {
|
|||||||
funcSvc: fsvc,
|
funcSvc: fsvc,
|
||||||
err: err,
|
err: err,
|
||||||
}
|
}
|
||||||
executor.fsCreateWg.Delete(crd.CacheKeyURFromMeta(fnMetadata))
|
executor.fsCreateWg.Delete(fnkeyUR)
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}()
|
}()
|
||||||
} else {
|
} else {
|
||||||
// There's an existing request for this function, wait for it to finish
|
// There's an existing request for this function, wait for it to finish
|
||||||
go func() {
|
go func() {
|
||||||
executor.logger.Debug("waiting for concurrent request for the same function",
|
executor.logger.Debug("waiting for concurrent request for the same function",
|
||||||
zap.Any("function", fnMetadata))
|
zap.String("function", fnName.String()))
|
||||||
wg, ok := wg.(*sync.WaitGroup)
|
wg, ok := wg.(*sync.WaitGroup)
|
||||||
if !ok {
|
if !ok {
|
||||||
err := fmt.Errorf("could not convert value to workgroup for function %v in namespace %v", fnMetadata.Name, fnMetadata.Namespace)
|
err := fmt.Errorf("could not convert value to workgroup for function %s", fnName)
|
||||||
req.respChan <- &createFuncServiceResponse{
|
req.respChan <- &createFuncServiceResponse{
|
||||||
funcSvc: nil,
|
funcSvc: nil,
|
||||||
err: err,
|
err: err,
|
||||||
@@ -201,7 +203,7 @@ func (executor *Executor) serveCreateFuncServices() {
|
|||||||
// It normally happened if there are multiple requests are
|
// It normally happened if there are multiple requests are
|
||||||
// waiting for the same function and executor failed to cre-
|
// waiting for the same function and executor failed to cre-
|
||||||
// ate service for function.
|
// ate service for function.
|
||||||
err = errors.Wrapf(err, "error getting service for function %v in namespace %v", fnMetadata.Name, fnMetadata.Namespace)
|
err = errors.Wrapf(err, "error getting service for function %s", fnName)
|
||||||
req.respChan <- &createFuncServiceResponse{
|
req.respChan <- &createFuncServiceResponse{
|
||||||
funcSvc: fsvc,
|
funcSvc: fsvc,
|
||||||
err: err,
|
err: err,
|
||||||
@@ -221,7 +223,7 @@ func (executor *Executor) createServiceForFunction(ctx context.Context, fn *fv1.
|
|||||||
t := fn.Spec.InvokeStrategy.ExecutionStrategy.ExecutorType
|
t := fn.Spec.InvokeStrategy.ExecutionStrategy.ExecutorType
|
||||||
e, ok := executor.executorTypes[t]
|
e, ok := executor.executorTypes[t]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.Errorf("Unknown executor type '%v'", t)
|
return nil, errors.Errorf("Unknown executor type '%s'", t)
|
||||||
}
|
}
|
||||||
|
|
||||||
fsvc, fsvcErr := e.GetFuncSvc(ctx, fn)
|
fsvc, fsvcErr := e.GetFuncSvc(ctx, fn)
|
||||||
@@ -242,7 +244,7 @@ func (executor *Executor) getFunctionServiceFromCache(ctx context.Context, fn *f
|
|||||||
t := fn.Spec.InvokeStrategy.ExecutionStrategy.ExecutorType
|
t := fn.Spec.InvokeStrategy.ExecutionStrategy.ExecutorType
|
||||||
e, ok := executor.executorTypes[t]
|
e, ok := executor.executorTypes[t]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.Errorf("Unknown executor type '%v'", t)
|
return nil, errors.Errorf("Unknown executor type '%s'", t)
|
||||||
}
|
}
|
||||||
return e.GetFuncSvcFromCache(ctx, fn)
|
return e.GetFuncSvcFromCache(ctx, fn)
|
||||||
}
|
}
|
||||||
@@ -277,7 +279,7 @@ func StartExecutor(ctx context.Context, clientGen crd.ClientGeneratorInterface,
|
|||||||
executorInstanceID := strings.ToLower(uniuri.NewLen(8))
|
executorInstanceID := strings.ToLower(uniuri.NewLen(8))
|
||||||
|
|
||||||
podSpecPatch, err := util.GetSpecFromConfigMap(fv1.RuntimePodSpecPath)
|
podSpecPatch, err := util.GetSpecFromConfigMap(fv1.RuntimePodSpecPath)
|
||||||
if err != nil {
|
if err != nil && !os.IsNotExist(err) {
|
||||||
logger.Warn("error reading data for pod spec patch", zap.String("path", fv1.RuntimePodSpecPath), zap.Error(err))
|
logger.Warn("error reading data for pod spec patch", zap.String("path", fv1.RuntimePodSpecPath), zap.Error(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,9 +18,9 @@ package container
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
multierror "github.com/hashicorp/go-multierror"
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
apiv1 "k8s.io/api/core/v1"
|
apiv1 "k8s.io/api/core/v1"
|
||||||
k8s_err "k8s.io/apimachinery/pkg/api/errors"
|
k8s_err "k8s.io/apimachinery/pkg/api/errors"
|
||||||
@@ -66,7 +66,7 @@ func (cn *Container) getResources(fn *fv1.Function) apiv1.ResourceRequirements {
|
|||||||
|
|
||||||
// cleanupContainer cleans all kubernetes objects related to function
|
// cleanupContainer cleans all kubernetes objects related to function
|
||||||
func (cn *Container) cleanupContainer(ctx context.Context, ns string, name string) error {
|
func (cn *Container) cleanupContainer(ctx context.Context, ns string, name string) error {
|
||||||
result := &multierror.Error{}
|
var result error
|
||||||
|
|
||||||
err := cn.deleteSvc(ctx, ns, name)
|
err := cn.deleteSvc(ctx, ns, name)
|
||||||
if err != nil && !k8s_err.IsNotFound(err) {
|
if err != nil && !k8s_err.IsNotFound(err) {
|
||||||
@@ -74,7 +74,7 @@ func (cn *Container) cleanupContainer(ctx context.Context, ns string, name strin
|
|||||||
zap.Error(err),
|
zap.Error(err),
|
||||||
zap.String("function_name", name),
|
zap.String("function_name", name),
|
||||||
zap.String("function_namespace", ns))
|
zap.String("function_namespace", ns))
|
||||||
result = multierror.Append(result, err)
|
result = errors.Join(result, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = cn.hpaops.DeleteHpa(ctx, ns, name)
|
err = cn.hpaops.DeleteHpa(ctx, ns, name)
|
||||||
@@ -83,7 +83,7 @@ func (cn *Container) cleanupContainer(ctx context.Context, ns string, name strin
|
|||||||
zap.Error(err),
|
zap.Error(err),
|
||||||
zap.String("function_name", name),
|
zap.String("function_name", name),
|
||||||
zap.String("function_namespace", ns))
|
zap.String("function_namespace", ns))
|
||||||
result = multierror.Append(result, err)
|
result = errors.Join(result, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = cn.deleteDeployment(ctx, ns, name)
|
err = cn.deleteDeployment(ctx, ns, name)
|
||||||
@@ -92,10 +92,10 @@ func (cn *Container) cleanupContainer(ctx context.Context, ns string, name strin
|
|||||||
zap.Error(err),
|
zap.Error(err),
|
||||||
zap.String("function_name", name),
|
zap.String("function_name", name),
|
||||||
zap.String("function_namespace", ns))
|
zap.String("function_namespace", ns))
|
||||||
result = multierror.Append(result, err)
|
result = errors.Join(result, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.ErrorOrNil()
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// referencedResourcesRVSum returns the sum of resource version of all resources the function references to.
|
// referencedResourcesRVSum returns the sum of resource version of all resources the function references to.
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package container
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
@@ -26,8 +27,6 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
multierror "github.com/hashicorp/go-multierror"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
apiv1 "k8s.io/api/core/v1"
|
apiv1 "k8s.io/api/core/v1"
|
||||||
k8sErrs "k8s.io/apimachinery/pkg/api/errors"
|
k8sErrs "k8s.io/apimachinery/pkg/api/errors"
|
||||||
@@ -142,7 +141,7 @@ func MakeContainer(
|
|||||||
for _, factory := range finformerFactory {
|
for _, factory := range finformerFactory {
|
||||||
_, err := factory.Core().V1().Functions().Informer().AddEventHandler(caaf.FuncInformerHandler(ctx))
|
_, err := factory.Core().V1().Functions().Informer().AddEventHandler(caaf.FuncInformerHandler(ctx))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "failed to add event handler for function informer")
|
return nil, fmt.Errorf("failed to add event handler for function informer: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return caaf, nil
|
return caaf, nil
|
||||||
@@ -269,7 +268,7 @@ func (caaf *Container) RefreshFuncPods(ctx context.Context, logger *zap.Logger,
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
patch := fmt.Sprintf(`{"spec" : {"template": {"spec":{"containers":[{"name": "%s", "env":[{"name": "%s", "value": "%v"}]}]}}}}`,
|
patch := fmt.Sprintf(`{"spec" : {"template": {"spec":{"containers":[{"name": "%s", "env":[{"name": "%s", "value": "%d"}]}]}}}}`,
|
||||||
f.ObjectMeta.Name, fv1.ResourceVersionCount, rvCount)
|
f.ObjectMeta.Name, fv1.ResourceVersionCount, rvCount)
|
||||||
|
|
||||||
_, err = caaf.kubernetesClient.AppsV1().Deployments(deployment.ObjectMeta.Namespace).Patch(ctx, deployment.ObjectMeta.Name,
|
_, err = caaf.kubernetesClient.AppsV1().Deployments(deployment.ObjectMeta.Namespace).Patch(ctx, deployment.ObjectMeta.Name,
|
||||||
@@ -318,29 +317,29 @@ func (caaf *Container) AdoptExistingResources(ctx context.Context) {
|
|||||||
func (caaf *Container) CleanupOldExecutorObjects(ctx context.Context) {
|
func (caaf *Container) CleanupOldExecutorObjects(ctx context.Context) {
|
||||||
caaf.logger.Info("CaaF starts to clean orphaned resources", zap.String("instanceID", caaf.instanceID))
|
caaf.logger.Info("CaaF starts to clean orphaned resources", zap.String("instanceID", caaf.instanceID))
|
||||||
|
|
||||||
errs := &multierror.Error{}
|
var errs error
|
||||||
listOpts := metav1.ListOptions{
|
listOpts := metav1.ListOptions{
|
||||||
LabelSelector: labels.Set(map[string]string{fv1.EXECUTOR_TYPE: string(fv1.ExecutorTypeContainer)}).AsSelector().String(),
|
LabelSelector: labels.Set(map[string]string{fv1.EXECUTOR_TYPE: string(fv1.ExecutorTypeContainer)}).AsSelector().String(),
|
||||||
}
|
}
|
||||||
|
|
||||||
err := reaper.CleanupHpa(ctx, caaf.logger, caaf.kubernetesClient, caaf.instanceID, listOpts)
|
err := reaper.CleanupHpa(ctx, caaf.logger, caaf.kubernetesClient, caaf.instanceID, listOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs = multierror.Append(errs, err)
|
errs = errors.Join(errs, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = reaper.CleanupDeployments(ctx, caaf.logger, caaf.kubernetesClient, caaf.instanceID, listOpts)
|
err = reaper.CleanupDeployments(ctx, caaf.logger, caaf.kubernetesClient, caaf.instanceID, listOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs = multierror.Append(errs, err)
|
errs = errors.Join(errs, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = reaper.CleanupServices(ctx, caaf.logger, caaf.kubernetesClient, caaf.instanceID, listOpts)
|
err = reaper.CleanupServices(ctx, caaf.logger, caaf.kubernetesClient, caaf.instanceID, listOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs = multierror.Append(errs, err)
|
errs = errors.Join(errs, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if errs.ErrorOrNil() != nil {
|
if errs != nil {
|
||||||
// TODO retry reaper; logged and ignored for now
|
// TODO retry reaper; logged and ignored for now
|
||||||
caaf.logger.Error("Failed to cleanup old executor objects", zap.Error(err))
|
caaf.logger.Error("Failed to cleanup old executor objects", zap.Error(errs))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -361,7 +360,7 @@ func (caaf *Container) createFunction(ctx context.Context, fn *fv1.Function) (*f
|
|||||||
zap.Error(err),
|
zap.Error(err),
|
||||||
zap.String("function_name", fn.ObjectMeta.Name),
|
zap.String("function_name", fn.ObjectMeta.Name),
|
||||||
zap.String("function_namespace", fn.ObjectMeta.Namespace))
|
zap.String("function_namespace", fn.ObjectMeta.Namespace))
|
||||||
return nil, errors.Wrapf(err, "%s %s_%s", e, fn.ObjectMeta.Name, fn.ObjectMeta.Namespace)
|
return nil, fmt.Errorf("error creating k8s resources for function %s/%s: %w", fn.ObjectMeta.Namespace, fn.ObjectMeta.Name, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fsvc, ok := fsvcObj.(*fscache.FuncSvc)
|
fsvc, ok := fsvcObj.(*fscache.FuncSvc)
|
||||||
@@ -378,7 +377,7 @@ func (caaf *Container) deleteFunction(ctx context.Context, fn *fv1.Function) err
|
|||||||
}
|
}
|
||||||
err := caaf.fnDelete(ctx, fn)
|
err := caaf.fnDelete(ctx, fn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errors.Wrapf(err, "error deleting kubernetes objects of function %v", fn.ObjectMeta)
|
return fmt.Errorf("error deleting kubernetes objects of function %s: %w", k8sCache.MetaObjectToName(fn), err)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -408,22 +407,22 @@ func (caaf *Container) fnCreate(ctx context.Context, fn *fv1.Function) (*fscache
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
caaf.logger.Error("error creating service", zap.Error(err), zap.String("service", objName))
|
caaf.logger.Error("error creating service", zap.Error(err), zap.String("service", objName))
|
||||||
go cleanupFunc(ns, objName)
|
go cleanupFunc(ns, objName)
|
||||||
return nil, errors.Wrapf(err, "error creating service %v", objName)
|
return nil, fmt.Errorf("error creating service %s: %w", objName, err)
|
||||||
}
|
}
|
||||||
svcAddress := fmt.Sprintf("%v.%v", svc.Name, svc.Namespace)
|
svcAddress := fmt.Sprintf("%s.%s", svc.Name, svc.Namespace)
|
||||||
|
|
||||||
depl, err := caaf.createOrGetDeployment(ctx, fn, objName, deployLabels, deployAnnotations, ns)
|
depl, err := caaf.createOrGetDeployment(ctx, fn, objName, deployLabels, deployAnnotations, ns)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
caaf.logger.Error("error creating deployment", zap.Error(err), zap.String("deployment", objName))
|
caaf.logger.Error("error creating deployment", zap.Error(err), zap.String("deployment", objName))
|
||||||
go cleanupFunc(ns, objName)
|
go cleanupFunc(ns, objName)
|
||||||
return nil, errors.Wrapf(err, "error creating deployment %v", objName)
|
return nil, fmt.Errorf("error creating deployment %s: %w", objName, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
hpa, err := caaf.hpaops.CreateOrGetHpa(ctx, objName, &fn.Spec.InvokeStrategy.ExecutionStrategy, depl, deployLabels, deployAnnotations)
|
hpa, err := caaf.hpaops.CreateOrGetHpa(ctx, objName, &fn.Spec.InvokeStrategy.ExecutionStrategy, depl, deployLabels, deployAnnotations)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
caaf.logger.Error("error creating HPA", zap.Error(err), zap.String("hpa", objName))
|
caaf.logger.Error("error creating HPA", zap.Error(err), zap.String("hpa", objName))
|
||||||
go cleanupFunc(ns, objName)
|
go cleanupFunc(ns, objName)
|
||||||
return nil, errors.Wrapf(err, "error creating the HPA %v", objName)
|
return nil, fmt.Errorf("error creating HPA %s: %w", objName, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
kubeObjRefs := []apiv1.ObjectReference{
|
kubeObjRefs := []apiv1.ObjectReference{
|
||||||
@@ -515,8 +514,7 @@ func (caaf *Container) updateFunction(ctx context.Context, oldFn *fv1.Function,
|
|||||||
|
|
||||||
fsvc, err := caaf.fsCache.GetByFunctionUID(newFn.ObjectMeta.UID)
|
fsvc, err := caaf.fsCache.GetByFunctionUID(newFn.ObjectMeta.UID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errors.Wrapf(err, "error updating function due to unable to find function service cache: %v", oldFn)
|
return fmt.Errorf("error updating function due to unable to find function service cache %s: %w", k8sCache.MetaObjectToName(oldFn), err)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hpa, err := caaf.hpaops.GetHpa(ctx, ns, fsvc.Name)
|
hpa, err := caaf.hpaops.GetHpa(ctx, ns, fsvc.Name)
|
||||||
@@ -596,8 +594,7 @@ func (caaf *Container) updateFuncDeployment(ctx context.Context, fn *fv1.Functio
|
|||||||
|
|
||||||
fsvc, err := caaf.fsCache.GetByFunctionUID(fn.ObjectMeta.UID)
|
fsvc, err := caaf.fsCache.GetByFunctionUID(fn.ObjectMeta.UID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errors.Wrapf(err, "error updating function due to unable to find function service cache: %v", fn)
|
return fmt.Errorf("error updating function due to unable to find function service cache %s: %w", k8sCache.MetaObjectToName(fn), err)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
fnObjName := fsvc.Name
|
fnObjName := fsvc.Name
|
||||||
|
|
||||||
@@ -634,7 +631,7 @@ func (caaf *Container) updateFuncDeployment(ctx context.Context, fn *fv1.Functio
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (caaf *Container) fnDelete(ctx context.Context, fn *fv1.Function) error {
|
func (caaf *Container) fnDelete(ctx context.Context, fn *fv1.Function) error {
|
||||||
multierr := &multierror.Error{}
|
var multierr error
|
||||||
|
|
||||||
// GetByFunction uses resource version as part of cache key, however,
|
// GetByFunction uses resource version as part of cache key, however,
|
||||||
// the resource version in function metadata will be changed when a function
|
// the resource version in function metadata will be changed when a function
|
||||||
@@ -643,16 +640,14 @@ func (caaf *Container) fnDelete(ctx context.Context, fn *fv1.Function) error {
|
|||||||
// fsvc entry.
|
// fsvc entry.
|
||||||
fsvc, err := caaf.fsCache.GetByFunctionUID(fn.ObjectMeta.UID)
|
fsvc, err := caaf.fsCache.GetByFunctionUID(fn.ObjectMeta.UID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errors.Wrap(err, fmt.Sprintf("fsvc not found in cache: %v", fn.ObjectMeta))
|
return fmt.Errorf("fsvc not found in cache %s: %w", k8sCache.MetaObjectToName(fn), err)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
objName := fsvc.Name
|
objName := fsvc.Name
|
||||||
|
|
||||||
_, err = caaf.fsCache.DeleteOld(fsvc, time.Second*0)
|
_, err = caaf.fsCache.DeleteOld(fsvc, time.Second*0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
multierr = multierror.Append(multierr,
|
multierr = errors.Join(multierr, fmt.Errorf("error deleting function from cache: %w", err))
|
||||||
errors.Wrapf(err, "error deleting the function from cache"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// to support backward compatibility, if the function was created in default ns, we fall back to creating the
|
// to support backward compatibility, if the function was created in default ns, we fall back to creating the
|
||||||
@@ -660,9 +655,8 @@ func (caaf *Container) fnDelete(ctx context.Context, fn *fv1.Function) error {
|
|||||||
ns := caaf.nsResolver.GetFunctionNS(fn.ObjectMeta.Namespace)
|
ns := caaf.nsResolver.GetFunctionNS(fn.ObjectMeta.Namespace)
|
||||||
|
|
||||||
err = caaf.cleanupContainer(ctx, ns, objName)
|
err = caaf.cleanupContainer(ctx, ns, objName)
|
||||||
multierr = multierror.Append(multierr, err)
|
multierr = errors.Join(multierr, err)
|
||||||
|
return multierr
|
||||||
return multierr.ErrorOrNil()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// getObjName returns a unique name for kubernetes objects of function
|
// getObjName returns a unique name for kubernetes objects of function
|
||||||
|
|||||||
@@ -231,7 +231,7 @@ func (cn *Container) getDeploymentSpec(ctx context.Context, fn *fv1.Function, ta
|
|||||||
Exec: &apiv1.ExecAction{
|
Exec: &apiv1.ExecAction{
|
||||||
Command: []string{
|
Command: []string{
|
||||||
"/bin/sleep",
|
"/bin/sleep",
|
||||||
fmt.Sprintf("%v", gracePeriodSeconds),
|
fmt.Sprintf("%d", gracePeriodSeconds),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -239,7 +239,7 @@ func (cn *Container) getDeploymentSpec(ctx context.Context, fn *fv1.Function, ta
|
|||||||
Env: []apiv1.EnvVar{
|
Env: []apiv1.EnvVar{
|
||||||
{
|
{
|
||||||
Name: fv1.ResourceVersionCount,
|
Name: fv1.ResourceVersionCount,
|
||||||
Value: fmt.Sprintf("%v", rvCount),
|
Value: fmt.Sprintf("%d", rvCount),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
EnvFrom: envFromSources,
|
EnvFrom: envFromSources,
|
||||||
|
|||||||
@@ -18,11 +18,11 @@ package newdeploy
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
multierror "github.com/hashicorp/go-multierror"
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
appsv1 "k8s.io/api/apps/v1"
|
appsv1 "k8s.io/api/apps/v1"
|
||||||
apiv1 "k8s.io/api/core/v1"
|
apiv1 "k8s.io/api/core/v1"
|
||||||
@@ -195,7 +195,7 @@ func (deploy *NewDeploy) getDeploymentSpec(ctx context.Context, fn *fv1.Function
|
|||||||
Exec: &apiv1.ExecAction{
|
Exec: &apiv1.ExecAction{
|
||||||
Command: []string{
|
Command: []string{
|
||||||
"/bin/sleep",
|
"/bin/sleep",
|
||||||
fmt.Sprintf("%v", gracePeriodSeconds),
|
fmt.Sprintf("%d", gracePeriodSeconds),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -238,7 +238,7 @@ func (deploy *NewDeploy) getDeploymentSpec(ctx context.Context, fn *fv1.Function
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
pod.Spec = *updatedPodSpec
|
pod.Spec = *updatedPodSpec
|
||||||
} else {
|
} else {
|
||||||
deploy.logger.Warn("Failed to merge the specs: %v", zap.Error(err))
|
deploy.logger.Warn("Failed to merge the specs", zap.Error(err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -419,7 +419,7 @@ func (deploy *NewDeploy) waitForDeploy(ctx context.Context, depl *appsv1.Deploym
|
|||||||
|
|
||||||
// cleanupNewdeploy cleans all kubernetes objects related to function
|
// cleanupNewdeploy cleans all kubernetes objects related to function
|
||||||
func (deploy *NewDeploy) cleanupNewdeploy(ctx context.Context, ns string, name string) error {
|
func (deploy *NewDeploy) cleanupNewdeploy(ctx context.Context, ns string, name string) error {
|
||||||
result := &multierror.Error{}
|
var result error
|
||||||
|
|
||||||
err := deploy.deleteSvc(ctx, ns, name)
|
err := deploy.deleteSvc(ctx, ns, name)
|
||||||
if err != nil && !k8s_err.IsNotFound(err) {
|
if err != nil && !k8s_err.IsNotFound(err) {
|
||||||
@@ -427,7 +427,7 @@ func (deploy *NewDeploy) cleanupNewdeploy(ctx context.Context, ns string, name s
|
|||||||
zap.Error(err),
|
zap.Error(err),
|
||||||
zap.String("function_name", name),
|
zap.String("function_name", name),
|
||||||
zap.String("function_namespace", ns))
|
zap.String("function_namespace", ns))
|
||||||
result = multierror.Append(result, err)
|
result = errors.Join(result, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = deploy.hpaops.DeleteHpa(ctx, ns, name)
|
err = deploy.hpaops.DeleteHpa(ctx, ns, name)
|
||||||
@@ -436,7 +436,7 @@ func (deploy *NewDeploy) cleanupNewdeploy(ctx context.Context, ns string, name s
|
|||||||
zap.Error(err),
|
zap.Error(err),
|
||||||
zap.String("function_name", name),
|
zap.String("function_name", name),
|
||||||
zap.String("function_namespace", ns))
|
zap.String("function_namespace", ns))
|
||||||
result = multierror.Append(result, err)
|
result = errors.Join(result, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = deploy.deleteDeployment(ctx, ns, name)
|
err = deploy.deleteDeployment(ctx, ns, name)
|
||||||
@@ -445,10 +445,10 @@ func (deploy *NewDeploy) cleanupNewdeploy(ctx context.Context, ns string, name s
|
|||||||
zap.Error(err),
|
zap.Error(err),
|
||||||
zap.String("function_name", name),
|
zap.String("function_name", name),
|
||||||
zap.String("function_namespace", ns))
|
zap.String("function_namespace", ns))
|
||||||
result = multierror.Append(result, err)
|
result = errors.Join(result, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.ErrorOrNil()
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// referencedResourcesRVSum returns the sum of resource version of all resources the function references to.
|
// referencedResourcesRVSum returns the sum of resource version of all resources the function references to.
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package newdeploy
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
@@ -26,8 +27,6 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
multierror "github.com/hashicorp/go-multierror"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
autoscalingv1 "k8s.io/api/autoscaling/v1"
|
autoscalingv1 "k8s.io/api/autoscaling/v1"
|
||||||
apiv1 "k8s.io/api/core/v1"
|
apiv1 "k8s.io/api/core/v1"
|
||||||
@@ -338,27 +337,27 @@ func (deploy *NewDeploy) AdoptExistingResources(ctx context.Context) {
|
|||||||
func (deploy *NewDeploy) CleanupOldExecutorObjects(ctx context.Context) {
|
func (deploy *NewDeploy) CleanupOldExecutorObjects(ctx context.Context) {
|
||||||
deploy.logger.Info("Newdeploy starts to clean orphaned resources", zap.String("instanceID", deploy.instanceID))
|
deploy.logger.Info("Newdeploy starts to clean orphaned resources", zap.String("instanceID", deploy.instanceID))
|
||||||
|
|
||||||
errs := &multierror.Error{}
|
var errs error
|
||||||
listOpts := metav1.ListOptions{
|
listOpts := metav1.ListOptions{
|
||||||
LabelSelector: labels.Set(map[string]string{fv1.EXECUTOR_TYPE: string(fv1.ExecutorTypeNewdeploy)}).AsSelector().String(),
|
LabelSelector: labels.Set(map[string]string{fv1.EXECUTOR_TYPE: string(fv1.ExecutorTypeNewdeploy)}).AsSelector().String(),
|
||||||
}
|
}
|
||||||
|
|
||||||
err := reaper.CleanupHpa(ctx, deploy.logger, deploy.kubernetesClient, deploy.instanceID, listOpts)
|
err := reaper.CleanupHpa(ctx, deploy.logger, deploy.kubernetesClient, deploy.instanceID, listOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs = multierror.Append(errs, err)
|
errs = errors.Join(errs, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = reaper.CleanupDeployments(ctx, deploy.logger, deploy.kubernetesClient, deploy.instanceID, listOpts)
|
err = reaper.CleanupDeployments(ctx, deploy.logger, deploy.kubernetesClient, deploy.instanceID, listOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs = multierror.Append(errs, err)
|
errs = errors.Join(errs, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = reaper.CleanupServices(ctx, deploy.logger, deploy.kubernetesClient, deploy.instanceID, listOpts)
|
err = reaper.CleanupServices(ctx, deploy.logger, deploy.kubernetesClient, deploy.instanceID, listOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs = multierror.Append(errs, err)
|
errs = errors.Join(errs, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if errs.ErrorOrNil() != nil {
|
if errs != nil {
|
||||||
// TODO retry reaper; logged and ignored for now
|
// TODO retry reaper; logged and ignored for now
|
||||||
deploy.logger.Error("Failed to cleanup old executor objects", zap.Error(err))
|
deploy.logger.Error("Failed to cleanup old executor objects", zap.Error(err))
|
||||||
}
|
}
|
||||||
@@ -398,7 +397,7 @@ func (deploy *NewDeploy) createFunction(ctx context.Context, fn *fv1.Function) (
|
|||||||
zap.Error(err),
|
zap.Error(err),
|
||||||
zap.String("function_name", fn.ObjectMeta.Name),
|
zap.String("function_name", fn.ObjectMeta.Name),
|
||||||
zap.String("function_namespace", fn.ObjectMeta.Namespace))
|
zap.String("function_namespace", fn.ObjectMeta.Namespace))
|
||||||
return nil, errors.Wrapf(err, "%s %s_%s", e, fn.ObjectMeta.Name, fn.ObjectMeta.Namespace)
|
return nil, fmt.Errorf("error creating k8s resources for function %s: %w", k8sCache.MetaObjectToName(fn), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fsvc, ok := fsvcObj.(*fscache.FuncSvc)
|
fsvc, ok := fsvcObj.(*fscache.FuncSvc)
|
||||||
@@ -416,9 +415,9 @@ func (deploy *NewDeploy) deleteFunction(ctx context.Context, fn *fv1.Function) e
|
|||||||
}
|
}
|
||||||
err := deploy.fnDelete(ctx, fn)
|
err := deploy.fnDelete(ctx, fn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errors.Wrapf(err, "error deleting kubernetes objects of function %v", fn.ObjectMeta)
|
return fmt.Errorf("error deleting kubernetes objects of function %s: %w", k8sCache.MetaObjectToName(fn), err)
|
||||||
}
|
}
|
||||||
return err
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (deploy *NewDeploy) fnCreate(ctx context.Context, fn *fv1.Function) (*fscache.FuncSvc, error) {
|
func (deploy *NewDeploy) fnCreate(ctx context.Context, fn *fv1.Function) (*fscache.FuncSvc, error) {
|
||||||
@@ -453,22 +452,22 @@ func (deploy *NewDeploy) fnCreate(ctx context.Context, fn *fv1.Function) (*fscac
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
deploy.logger.Error("error creating service", zap.Error(err), zap.String("service", objName))
|
deploy.logger.Error("error creating service", zap.Error(err), zap.String("service", objName))
|
||||||
go cleanupFunc(context.Background(), ns, objName)
|
go cleanupFunc(context.Background(), ns, objName)
|
||||||
return nil, errors.Wrapf(err, "error creating service %v", objName)
|
return nil, fmt.Errorf("error creating service %s: %w", objName, err)
|
||||||
}
|
}
|
||||||
svcAddress := fmt.Sprintf("%v.%v", svc.Name, svc.Namespace)
|
svcAddress := fmt.Sprintf("%s.%s", svc.Name, svc.Namespace)
|
||||||
|
|
||||||
depl, err := deploy.createOrGetDeployment(ctx, fn, env, objName, deployLabels, deployAnnotations, ns)
|
depl, err := deploy.createOrGetDeployment(ctx, fn, env, objName, deployLabels, deployAnnotations, ns)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
deploy.logger.Error("error creating deployment", zap.Error(err), zap.String("deployment", objName))
|
deploy.logger.Error("error creating deployment", zap.Error(err), zap.String("deployment", objName))
|
||||||
go cleanupFunc(context.Background(), ns, objName)
|
go cleanupFunc(context.Background(), ns, objName)
|
||||||
return nil, errors.Wrapf(err, "error creating deployment %v", objName)
|
return nil, fmt.Errorf("error creating deployment %s: %w", objName, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
hpa, err := deploy.hpaops.CreateOrGetHpa(ctx, objName, &fn.Spec.InvokeStrategy.ExecutionStrategy, depl, deployLabels, deployAnnotations)
|
hpa, err := deploy.hpaops.CreateOrGetHpa(ctx, objName, &fn.Spec.InvokeStrategy.ExecutionStrategy, depl, deployLabels, deployAnnotations)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
deploy.logger.Error("error creating HPA", zap.Error(err), zap.String("hpa", objName))
|
deploy.logger.Error("error creating HPA", zap.Error(err), zap.String("hpa", objName))
|
||||||
go cleanupFunc(context.Background(), ns, objName)
|
go cleanupFunc(context.Background(), ns, objName)
|
||||||
return nil, errors.Wrapf(err, "error creating the HPA %v", objName)
|
return nil, fmt.Errorf("error creating HPA %s: %w", objName, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
kubeObjRefs := []apiv1.ObjectReference{
|
kubeObjRefs := []apiv1.ObjectReference{
|
||||||
@@ -564,8 +563,7 @@ func (deploy *NewDeploy) updateFunction(ctx context.Context, oldFn *fv1.Function
|
|||||||
|
|
||||||
fsvc, err := deploy.fsCache.GetByFunctionUID(newFn.ObjectMeta.UID)
|
fsvc, err := deploy.fsCache.GetByFunctionUID(newFn.ObjectMeta.UID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errors.Wrapf(err, "error updating function due to unable to find function service cache: %v", oldFn)
|
return fmt.Errorf("error updating function due to unable to find function service cache %s: %w", k8sCache.MetaObjectToName(oldFn), err)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hpa, err := deploy.hpaops.GetHpa(ctx, ns, fsvc.Name)
|
hpa, err := deploy.hpaops.GetHpa(ctx, ns, fsvc.Name)
|
||||||
@@ -651,8 +649,7 @@ func (deploy *NewDeploy) updateFunction(ctx context.Context, oldFn *fv1.Function
|
|||||||
func (deploy *NewDeploy) updateFuncDeployment(ctx context.Context, fn *fv1.Function, env *fv1.Environment) error {
|
func (deploy *NewDeploy) updateFuncDeployment(ctx context.Context, fn *fv1.Function, env *fv1.Environment) error {
|
||||||
fsvc, err := deploy.fsCache.GetByFunctionUID(fn.ObjectMeta.UID)
|
fsvc, err := deploy.fsCache.GetByFunctionUID(fn.ObjectMeta.UID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errors.Wrapf(err, "error updating function due to unable to find function service cache: %v", fn)
|
return fmt.Errorf("error updating function due to unable to find function service cache: %s: %w", k8sCache.MetaObjectToName(fn), err)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
fnObjName := fsvc.Name
|
fnObjName := fsvc.Name
|
||||||
|
|
||||||
@@ -690,7 +687,7 @@ func (deploy *NewDeploy) updateFuncDeployment(ctx context.Context, fn *fv1.Funct
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (deploy *NewDeploy) fnDelete(ctx context.Context, fn *fv1.Function) error {
|
func (deploy *NewDeploy) fnDelete(ctx context.Context, fn *fv1.Function) error {
|
||||||
multierr := &multierror.Error{}
|
var errs error
|
||||||
|
|
||||||
// GetByFunction uses resource version as part of cache key, however,
|
// GetByFunction uses resource version as part of cache key, however,
|
||||||
// the resource version in function metadata will be changed when a function
|
// the resource version in function metadata will be changed when a function
|
||||||
@@ -699,16 +696,14 @@ func (deploy *NewDeploy) fnDelete(ctx context.Context, fn *fv1.Function) error {
|
|||||||
// fsvc entry.
|
// fsvc entry.
|
||||||
fsvc, err := deploy.fsCache.GetByFunctionUID(fn.ObjectMeta.UID)
|
fsvc, err := deploy.fsCache.GetByFunctionUID(fn.ObjectMeta.UID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errors.Wrap(err, fmt.Sprintf("fsvc not found in cache: %v", fn.ObjectMeta))
|
return fmt.Errorf("fsvc not found in cache: %s: %w", k8sCache.MetaObjectToName(fn), err)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
objName := fsvc.Name
|
objName := fsvc.Name
|
||||||
|
|
||||||
_, err = deploy.fsCache.DeleteOld(fsvc, time.Second*0)
|
_, err = deploy.fsCache.DeleteOld(fsvc, time.Second*0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
multierr = multierror.Append(multierr,
|
errs = errors.Join(errs, fmt.Errorf("error deleting the function from cache"))
|
||||||
errors.Wrap(err, "error deleting the function from cache"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// to support backward compatibility, if the function was created in default ns, we fall back to creating the
|
// to support backward compatibility, if the function was created in default ns, we fall back to creating the
|
||||||
@@ -716,9 +711,9 @@ func (deploy *NewDeploy) fnDelete(ctx context.Context, fn *fv1.Function) error {
|
|||||||
ns := deploy.nsResolver.GetFunctionNS(fn.ObjectMeta.Namespace)
|
ns := deploy.nsResolver.GetFunctionNS(fn.ObjectMeta.Namespace)
|
||||||
|
|
||||||
err = deploy.cleanupNewdeploy(ctx, ns, objName)
|
err = deploy.cleanupNewdeploy(ctx, ns, objName)
|
||||||
multierr = multierror.Append(multierr, err)
|
errs = errors.Join(errs, err)
|
||||||
|
|
||||||
return multierr.ErrorOrNil()
|
return errs
|
||||||
}
|
}
|
||||||
|
|
||||||
// getObjName returns a unique name for kubernetes objects of function
|
// getObjName returns a unique name for kubernetes objects of function
|
||||||
|
|||||||
@@ -324,13 +324,13 @@ func (gp *GenericPool) choosePod(ctx context.Context, newLabels map[string]strin
|
|||||||
// So we have to check both of them to ensure the patch success.
|
// So we have to check both of them to ensure the patch success.
|
||||||
for k, v := range newLabels {
|
for k, v := range newLabels {
|
||||||
if newPod.Labels[k] != v {
|
if newPod.Labels[k] != v {
|
||||||
return "", nil, errors.Errorf("value of necessary labels '%v' mismatch: want '%v', get '%v'",
|
return "", nil, errors.Errorf("value of necessary labels '%s' mismatch: want '%s', get '%v'",
|
||||||
k, v, newPod.Labels[k])
|
k, v, newPod.Labels[k])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for k, v := range annotations {
|
for k, v := range annotations {
|
||||||
if newPod.Annotations[k] != v {
|
if newPod.Annotations[k] != v {
|
||||||
return "", nil, errors.Errorf("value of necessary annotations '%v' mismatch: want '%v', get '%v'",
|
return "", nil, errors.Errorf("value of necessary annotations '%s' mismatch: want '%s', get '%v'",
|
||||||
k, v, newPod.Annotations[k])
|
k, v, newPod.Annotations[k])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -388,9 +388,9 @@ func (gp *GenericPool) getFetcherURL(podIP string) string {
|
|||||||
var baseURL string
|
var baseURL string
|
||||||
|
|
||||||
if isv6 { // We use bracket if the IP is in IPv6.
|
if isv6 { // We use bracket if the IP is in IPv6.
|
||||||
baseURL = fmt.Sprintf("http://[%v]:8000/", podIP)
|
baseURL = fmt.Sprintf("http://[%s]:8000/", podIP)
|
||||||
} else {
|
} else {
|
||||||
baseURL = fmt.Sprintf("http://%v:8000/", podIP)
|
baseURL = fmt.Sprintf("http://%s:8000/", podIP)
|
||||||
}
|
}
|
||||||
return baseURL
|
return baseURL
|
||||||
}
|
}
|
||||||
@@ -440,7 +440,7 @@ func (gp *GenericPool) specializePod(ctx context.Context, pod *apiv1.Pod, fn *fv
|
|||||||
// specialize pod with service
|
// specialize pod with service
|
||||||
if gp.useIstio {
|
if gp.useIstio {
|
||||||
svc := utils.GetFunctionIstioServiceName(fn.ObjectMeta.Name, fn.ObjectMeta.Namespace)
|
svc := utils.GetFunctionIstioServiceName(fn.ObjectMeta.Name, fn.ObjectMeta.Namespace)
|
||||||
podIP = fmt.Sprintf("%v.%v", svc, gp.fnNamespace)
|
podIP = fmt.Sprintf("%s.%s", svc, gp.fnNamespace)
|
||||||
}
|
}
|
||||||
|
|
||||||
// tell fetcher to get the function.
|
// tell fetcher to get the function.
|
||||||
@@ -548,7 +548,7 @@ func (gp *GenericPool) getFuncSvc(ctx context.Context, fn *fv1.Function) (*fscac
|
|||||||
|
|
||||||
var svcHost string
|
var svcHost string
|
||||||
if gp.useSvc && !gp.useIstio {
|
if gp.useSvc && !gp.useIstio {
|
||||||
svcName := fmt.Sprintf("svc-%v", fn.ObjectMeta.Name)
|
svcName := fmt.Sprintf("svc-%s", fn.ObjectMeta.Name)
|
||||||
if len(fn.ObjectMeta.UID) > 0 {
|
if len(fn.ObjectMeta.UID) > 0 {
|
||||||
svcName = fmt.Sprintf("%s-%v", svcName, fn.ObjectMeta.UID)
|
svcName = fmt.Sprintf("%s-%v", svcName, fn.ObjectMeta.UID)
|
||||||
}
|
}
|
||||||
@@ -560,7 +560,7 @@ func (gp *GenericPool) getFuncSvc(ctx context.Context, fn *fv1.Function) (*fscac
|
|||||||
}
|
}
|
||||||
if svc.ObjectMeta.Name != svcName {
|
if svc.ObjectMeta.Name != svcName {
|
||||||
go gp.scheduleDeletePod(context.Background(), pod.ObjectMeta.Name)
|
go gp.scheduleDeletePod(context.Background(), pod.ObjectMeta.Name)
|
||||||
return nil, errors.Errorf("sanity check failed for svc %v", svc.ObjectMeta.Name)
|
return nil, errors.Errorf("sanity check failed for svc %s", svc.ObjectMeta.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// the fission router isn't in the same namespace, so return a
|
// the fission router isn't in the same namespace, so return a
|
||||||
@@ -575,7 +575,7 @@ func (gp *GenericPool) getFuncSvc(ctx context.Context, fn *fv1.Function) (*fscac
|
|||||||
|
|
||||||
otelUtils.SpanTrackEvent(ctx, "addFunctionLabel", otelUtils.GetAttributesForPod(pod)...)
|
otelUtils.SpanTrackEvent(ctx, "addFunctionLabel", otelUtils.GetAttributesForPod(pod)...)
|
||||||
// patch svc-host and resource version to the pod annotations for new executor to adopt the pod
|
// patch svc-host and resource version to the pod annotations for new executor to adopt the pod
|
||||||
patch := fmt.Sprintf(`{"metadata":{"annotations":{"%v":"%v","%v":"%v"}}}`,
|
patch := fmt.Sprintf(`{"metadata":{"annotations":{"%s":"%s","%s":"%s"}}}`,
|
||||||
fv1.ANNOTATION_SVC_HOST, svcHost, fv1.FUNCTION_RESOURCE_VERSION, fn.ObjectMeta.ResourceVersion)
|
fv1.ANNOTATION_SVC_HOST, svcHost, fv1.FUNCTION_RESOURCE_VERSION, fn.ObjectMeta.ResourceVersion)
|
||||||
p, err := gp.kubernetesClient.CoreV1().Pods(pod.Namespace).Patch(ctx, pod.Name, k8sTypes.StrategicMergePatchType, []byte(patch), metav1.PatchOptions{})
|
p, err := gp.kubernetesClient.CoreV1().Pods(pod.Namespace).Patch(ctx, pod.Name, k8sTypes.StrategicMergePatchType, []byte(patch), metav1.PatchOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ func (gp *GenericPool) genDeploymentSpec(env *fv1.Environment) (*appsv1.Deployme
|
|||||||
Exec: &apiv1.ExecAction{
|
Exec: &apiv1.ExecAction{
|
||||||
Command: []string{
|
Command: []string{
|
||||||
"/bin/sleep",
|
"/bin/sleep",
|
||||||
fmt.Sprintf("%v", gracePeriodSeconds),
|
fmt.Sprintf("%d", gracePeriodSeconds),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -151,12 +151,11 @@ func (gp *GenericPool) genDeploymentSpec(env *fv1.Environment) (*appsv1.Deployme
|
|||||||
}
|
}
|
||||||
|
|
||||||
if gp.podSpecPatch != nil {
|
if gp.podSpecPatch != nil {
|
||||||
|
|
||||||
updatedPodSpec, err := util.MergePodSpec(&pod.Spec, gp.podSpecPatch)
|
updatedPodSpec, err := util.MergePodSpec(&pod.Spec, gp.podSpecPatch)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
pod.Spec = *updatedPodSpec
|
pod.Spec = *updatedPodSpec
|
||||||
} else {
|
} else {
|
||||||
gp.logger.Warn("Failed to merge the specs: %v", zap.Error(err))
|
gp.logger.Warn("Failed to merge the specs", zap.Error(err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package poolmgr
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
"os"
|
||||||
@@ -27,7 +28,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/fission/fission/pkg/executor/metrics"
|
"github.com/fission/fission/pkg/executor/metrics"
|
||||||
"github.com/hashicorp/go-multierror"
|
|
||||||
"go.opentelemetry.io/otel/attribute"
|
"go.opentelemetry.io/otel/attribute"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
apiv1 "k8s.io/api/core/v1"
|
apiv1 "k8s.io/api/core/v1"
|
||||||
@@ -366,7 +366,7 @@ func (gpm *GenericPoolManager) AdoptExistingResources(ctx context.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// create environment map for later use
|
// create environment map for later use
|
||||||
key := fmt.Sprintf("%v/%v", env.ObjectMeta.Namespace, env.ObjectMeta.Name)
|
key := fmt.Sprintf("%s/%s", env.ObjectMeta.Namespace, env.ObjectMeta.Name)
|
||||||
envMap[key] = env
|
envMap[key] = env
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -398,7 +398,7 @@ func (gpm *GenericPoolManager) AdoptExistingResources(ctx context.Context) {
|
|||||||
// avoid too many requests arrive Kubernetes API server at the same time.
|
// avoid too many requests arrive Kubernetes API server at the same time.
|
||||||
time.Sleep(time.Duration(rand.Intn(30)) * time.Millisecond)
|
time.Sleep(time.Duration(rand.Intn(30)) * time.Millisecond)
|
||||||
|
|
||||||
patch := fmt.Sprintf(`{"metadata":{"annotations":{"%v":"%v"}}}`, fv1.EXECUTOR_INSTANCEID_LABEL, gpm.instanceID)
|
patch := fmt.Sprintf(`{"metadata":{"annotations":{"%s":"%s"}}}`, fv1.EXECUTOR_INSTANCEID_LABEL, gpm.instanceID)
|
||||||
pod, err = gpm.kubernetesClient.CoreV1().Pods(pod.Namespace).Patch(ctx, pod.Name, k8sTypes.StrategicMergePatchType, []byte(patch), metav1.PatchOptions{})
|
pod, err = gpm.kubernetesClient.CoreV1().Pods(pod.Namespace).Patch(ctx, pod.Name, k8sTypes.StrategicMergePatchType, []byte(patch), metav1.PatchOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// just log the error since it won't affect the function serving
|
// just log the error since it won't affect the function serving
|
||||||
@@ -419,7 +419,7 @@ func (gpm *GenericPoolManager) AdoptExistingResources(ctx context.Context) {
|
|||||||
envName, ok5 := pod.Labels[fv1.ENVIRONMENT_NAME]
|
envName, ok5 := pod.Labels[fv1.ENVIRONMENT_NAME]
|
||||||
envNS, ok6 := pod.Labels[fv1.ENVIRONMENT_NAMESPACE]
|
envNS, ok6 := pod.Labels[fv1.ENVIRONMENT_NAMESPACE]
|
||||||
svcHost, ok7 := pod.Annotations[fv1.ANNOTATION_SVC_HOST]
|
svcHost, ok7 := pod.Annotations[fv1.ANNOTATION_SVC_HOST]
|
||||||
env, ok8 := envMap[fmt.Sprintf("%v/%v", envNS, envName)]
|
env, ok8 := envMap[fmt.Sprintf("%s/%s", envNS, envName)]
|
||||||
|
|
||||||
if !(ok1 && ok2 && ok3 && ok4 && ok5 && ok6 && ok7 && ok8) {
|
if !(ok1 && ok2 && ok3 && ok4 && ok5 && ok6 && ok7 && ok8) {
|
||||||
gpm.logger.Warn("failed to adopt pod for function due to lack of necessary information",
|
gpm.logger.Warn("failed to adopt pod for function due to lack of necessary information",
|
||||||
@@ -476,22 +476,22 @@ func (gpm *GenericPoolManager) AdoptExistingResources(ctx context.Context) {
|
|||||||
func (gpm *GenericPoolManager) CleanupOldExecutorObjects(ctx context.Context) {
|
func (gpm *GenericPoolManager) CleanupOldExecutorObjects(ctx context.Context) {
|
||||||
gpm.logger.Info("Poolmanager starts to clean orphaned resources", zap.String("instanceID", gpm.instanceID))
|
gpm.logger.Info("Poolmanager starts to clean orphaned resources", zap.String("instanceID", gpm.instanceID))
|
||||||
|
|
||||||
errs := &multierror.Error{}
|
var errs error
|
||||||
listOpts := metav1.ListOptions{
|
listOpts := metav1.ListOptions{
|
||||||
LabelSelector: labels.Set(map[string]string{fv1.EXECUTOR_TYPE: string(fv1.ExecutorTypePoolmgr)}).AsSelector().String(),
|
LabelSelector: labels.Set(map[string]string{fv1.EXECUTOR_TYPE: string(fv1.ExecutorTypePoolmgr)}).AsSelector().String(),
|
||||||
}
|
}
|
||||||
|
|
||||||
err := reaper.CleanupDeployments(ctx, gpm.logger, gpm.kubernetesClient, gpm.instanceID, listOpts)
|
err := reaper.CleanupDeployments(ctx, gpm.logger, gpm.kubernetesClient, gpm.instanceID, listOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs = multierror.Append(errs, err)
|
errs = errors.Join(errs, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = reaper.CleanupPods(ctx, gpm.logger, gpm.kubernetesClient, gpm.instanceID, listOpts)
|
err = reaper.CleanupPods(ctx, gpm.logger, gpm.kubernetesClient, gpm.instanceID, listOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs = multierror.Append(errs, err)
|
errs = errors.Join(errs, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if errs.ErrorOrNil() != nil {
|
if errs != nil {
|
||||||
// TODO retry reaper; logged and ignored for now
|
// TODO retry reaper; logged and ignored for now
|
||||||
gpm.logger.Error("Failed to cleanup old executor objects", zap.Error(err))
|
gpm.logger.Error("Failed to cleanup old executor objects", zap.Error(err))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package fscache
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
@@ -124,7 +125,7 @@ func (c *PoolCache) service() {
|
|||||||
c.cache[req.function] = NewFuncSvcGroup()
|
c.cache[req.function] = NewFuncSvcGroup()
|
||||||
c.cache[req.function].svcWaiting++
|
c.cache[req.function].svcWaiting++
|
||||||
resp.error = ferror.MakeError(ferror.ErrorNotFound,
|
resp.error = ferror.MakeError(ferror.ErrorNotFound,
|
||||||
fmt.Sprintf("function Name '%v' not found", req.function))
|
fmt.Sprintf("function Name '%s' not found", req.function))
|
||||||
req.responseChannel <- resp
|
req.responseChannel <- resp
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -325,11 +326,7 @@ func (c *PoolCache) service() {
|
|||||||
}
|
}
|
||||||
err := datawriter.Flush()
|
err := datawriter.Flush()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if resp.error == nil {
|
resp.error = errors.Join(resp.error, err)
|
||||||
resp.error = err
|
|
||||||
} else {
|
|
||||||
resp.error = fmt.Errorf("%v, %v", resp.error, err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
req.responseChannel <- resp
|
req.responseChannel <- resp
|
||||||
default:
|
default:
|
||||||
|
|||||||
+17
-17
@@ -17,11 +17,11 @@ limitations under the License.
|
|||||||
package util
|
package util
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"dario.cat/mergo"
|
"dario.cat/mergo"
|
||||||
"github.com/hashicorp/go-multierror"
|
|
||||||
apiv1 "k8s.io/api/core/v1"
|
apiv1 "k8s.io/api/core/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -40,18 +40,18 @@ func MergeContainer(dst *apiv1.Container, src *apiv1.Container) (*apiv1.Containe
|
|||||||
// to prevent any modification to the original obj
|
// to prevent any modification to the original obj
|
||||||
dstC := *dst
|
dstC := *dst
|
||||||
|
|
||||||
errs := &multierror.Error{}
|
var errs error
|
||||||
err := mergo.Merge(&dstC, src, mergo.WithAppendSlice, mergo.WithOverride)
|
err := mergo.Merge(&dstC, src, mergo.WithAppendSlice, mergo.WithOverride)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
errs = multierror.Append(errs,
|
errs = errors.Join(errs,
|
||||||
checkSliceConflicts("Name", dstC.Ports),
|
checkSliceConflicts("Name", dstC.Ports),
|
||||||
checkSliceConflicts("Name", dstC.Env),
|
checkSliceConflicts("Name", dstC.Env),
|
||||||
checkSliceConflicts("Name", dstC.VolumeMounts),
|
checkSliceConflicts("Name", dstC.VolumeMounts),
|
||||||
checkSliceConflicts("Name", dstC.VolumeDevices))
|
checkSliceConflicts("Name", dstC.VolumeDevices))
|
||||||
|
|
||||||
return &dstC, errs.ErrorOrNil()
|
return &dstC, errs
|
||||||
}
|
}
|
||||||
|
|
||||||
// MergePodSpec updates srcPodSpec with targetPodSpec fields if not empty
|
// MergePodSpec updates srcPodSpec with targetPodSpec fields if not empty
|
||||||
@@ -60,21 +60,21 @@ func MergePodSpec(srcPodSpec *apiv1.PodSpec, targetPodSpec *apiv1.PodSpec) (*api
|
|||||||
return srcPodSpec, nil
|
return srcPodSpec, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
multierr := &multierror.Error{}
|
var multierr error
|
||||||
|
|
||||||
// Get item from spec, if they exist in deployment - merge, else append
|
// Get item from spec, if they exist in deployment - merge, else append
|
||||||
// Same pattern for all lists (Mergo can not handle lists)
|
// Same pattern for all lists (Mergo can not handle lists)
|
||||||
// TODO: At some point this is better done with generics/reflection?
|
// TODO: At some point this is better done with generics/reflection?
|
||||||
cList, err := mergeContainerList(srcPodSpec.Containers, targetPodSpec.Containers)
|
cList, err := mergeContainerList(srcPodSpec.Containers, targetPodSpec.Containers)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
multierr = multierror.Append(multierr, err)
|
multierr = errors.Join(multierr, err)
|
||||||
} else {
|
} else {
|
||||||
srcPodSpec.Containers = cList
|
srcPodSpec.Containers = cList
|
||||||
}
|
}
|
||||||
|
|
||||||
cList, err = mergeContainerList(srcPodSpec.InitContainers, targetPodSpec.InitContainers)
|
cList, err = mergeContainerList(srcPodSpec.InitContainers, targetPodSpec.InitContainers)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
multierr = multierror.Append(multierr, err)
|
multierr = errors.Join(multierr, err)
|
||||||
} else {
|
} else {
|
||||||
srcPodSpec.InitContainers = cList
|
srcPodSpec.InitContainers = cList
|
||||||
}
|
}
|
||||||
@@ -82,7 +82,7 @@ func MergePodSpec(srcPodSpec *apiv1.PodSpec, targetPodSpec *apiv1.PodSpec) (*api
|
|||||||
// For volumes - if duplicate exist, throw error
|
// For volumes - if duplicate exist, throw error
|
||||||
vols, err := mergeVolumeLists(srcPodSpec.Volumes, targetPodSpec.Volumes)
|
vols, err := mergeVolumeLists(srcPodSpec.Volumes, targetPodSpec.Volumes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
multierr = multierror.Append(multierr, err)
|
multierr = errors.Join(multierr, err)
|
||||||
} else {
|
} else {
|
||||||
srcPodSpec.Volumes = vols
|
srcPodSpec.Volumes = vols
|
||||||
}
|
}
|
||||||
@@ -192,14 +192,14 @@ func MergePodSpec(srcPodSpec *apiv1.PodSpec, targetPodSpec *apiv1.PodSpec) (*api
|
|||||||
|
|
||||||
err = mergo.Merge(&srcPodSpec.NodeSelector, targetPodSpec.NodeSelector)
|
err = mergo.Merge(&srcPodSpec.NodeSelector, targetPodSpec.NodeSelector)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
multierr = multierror.Append(multierr, err)
|
multierr = errors.Join(multierr, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return srcPodSpec, multierr.ErrorOrNil()
|
return srcPodSpec, multierr
|
||||||
}
|
}
|
||||||
|
|
||||||
func mergeContainerList(dst []apiv1.Container, src []apiv1.Container) ([]apiv1.Container, error) {
|
func mergeContainerList(dst []apiv1.Container, src []apiv1.Container) ([]apiv1.Container, error) {
|
||||||
errs := &multierror.Error{}
|
var errs error
|
||||||
|
|
||||||
list := append(dst, src...)
|
list := append(dst, src...)
|
||||||
containers := make(map[string]*apiv1.Container, len(list))
|
containers := make(map[string]*apiv1.Container, len(list))
|
||||||
@@ -210,7 +210,7 @@ func mergeContainerList(dst []apiv1.Container, src []apiv1.Container) ([]apiv1.C
|
|||||||
newC, err := MergeContainer(container, &c)
|
newC, err := MergeContainer(container, &c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// record the error and continue
|
// record the error and continue
|
||||||
errs = multierror.Append(errs, err)
|
errs = errors.Join(errs, err)
|
||||||
} else {
|
} else {
|
||||||
containers[c.Name] = newC
|
containers[c.Name] = newC
|
||||||
}
|
}
|
||||||
@@ -224,8 +224,8 @@ func mergeContainerList(dst []apiv1.Container, src []apiv1.Container) ([]apiv1.C
|
|||||||
containerList = append(containerList, *c)
|
containerList = append(containerList, *c)
|
||||||
}
|
}
|
||||||
|
|
||||||
if errs.ErrorOrNil() != nil {
|
if errs != nil {
|
||||||
return nil, errs.ErrorOrNil()
|
return nil, errs
|
||||||
}
|
}
|
||||||
|
|
||||||
return containerList, nil
|
return containerList, nil
|
||||||
@@ -252,7 +252,7 @@ func checkSliceConflicts(field string, objs interface{}) (err error) {
|
|||||||
return fmt.Errorf("not a slice type: %v", reflect.TypeOf(objs))
|
return fmt.Errorf("not a slice type: %v", reflect.TypeOf(objs))
|
||||||
}
|
}
|
||||||
|
|
||||||
errs := &multierror.Error{}
|
var errs error
|
||||||
names := make(map[string]struct{})
|
names := make(map[string]struct{})
|
||||||
|
|
||||||
s := reflect.ValueOf(objs)
|
s := reflect.ValueOf(objs)
|
||||||
@@ -281,10 +281,10 @@ func checkSliceConflicts(field string, objs interface{}) (err error) {
|
|||||||
|
|
||||||
_, ok := names[f.String()]
|
_, ok := names[f.String()]
|
||||||
if ok {
|
if ok {
|
||||||
errs = multierror.Append(errs, fmt.Errorf("duplicate name in %v: %v", objType, f.String()))
|
errs = errors.Join(errs, fmt.Errorf("duplicate name in %v: %v", objType, f.String()))
|
||||||
} else {
|
} else {
|
||||||
names[f.String()] = struct{}{}
|
names[f.String()] = struct{}{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return errs.ErrorOrNil()
|
return errs
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -125,6 +125,10 @@ func ConvertConfigSecrets(ctx context.Context, fn *fv1.Function, kc kubernetes.I
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetSpecFromConfigMap(filePath string) (*apiv1.PodSpec, error) {
|
func GetSpecFromConfigMap(filePath string) (*apiv1.PodSpec, error) {
|
||||||
|
// check if file exists
|
||||||
|
if _, err := os.Stat(filePath); os.IsNotExist(err) {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
content, err := os.ReadFile(filePath)
|
content, err := os.ReadFile(filePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error reading YAML file %s: %w", filePath, err)
|
return nil, fmt.Errorf("error reading YAML file %s: %w", filePath, err)
|
||||||
|
|||||||
@@ -21,11 +21,20 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"go.uber.org/zap"
|
||||||
"sigs.k8s.io/yaml"
|
"sigs.k8s.io/yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetFeatureConfig reads the configMap file and unmarshals the config into a feature config struct
|
// GetFeatureConfig reads the configMap file and unmarshals the config into a feature config struct
|
||||||
func GetFeatureConfig() (*FeatureConfig, error) {
|
func GetFeatureConfig(logger *zap.Logger) (*FeatureConfig, error) {
|
||||||
|
featureConfig := &FeatureConfig{}
|
||||||
|
|
||||||
|
// check if the file exists
|
||||||
|
if _, err := os.Stat(FeatureConfigFile); os.IsNotExist(err) {
|
||||||
|
logger.Warn("using empty feature config as file not found", zap.String("configPath", FeatureConfigFile))
|
||||||
|
return featureConfig, nil
|
||||||
|
}
|
||||||
|
|
||||||
// read the file
|
// read the file
|
||||||
b64EncodedContent, err := os.ReadFile(FeatureConfigFile)
|
b64EncodedContent, err := os.ReadFile(FeatureConfigFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -39,7 +48,6 @@ func GetFeatureConfig() (*FeatureConfig, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// unmarshal into feature config
|
// unmarshal into feature config
|
||||||
featureConfig := &FeatureConfig{}
|
|
||||||
err = yaml.Unmarshal(yamlContent, featureConfig)
|
err = yaml.Unmarshal(yamlContent, featureConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error unmarshalling YAML config %v", err)
|
return nil, fmt.Errorf("error unmarshalling YAML config %v", err)
|
||||||
|
|||||||
@@ -65,17 +65,17 @@ func (opts *TestSubCommand) do(input cli.Input) error {
|
|||||||
Name: fnName,
|
Name: fnName,
|
||||||
Namespace: namespace,
|
Namespace: namespace,
|
||||||
}
|
}
|
||||||
routerURL := os.Getenv("FISSION_ROUTER")
|
|
||||||
if len(routerURL) != 0 {
|
|
||||||
console.Warn("The environment variable FISSION_ROUTER is no longer supported for this command")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Portforward to the fission router
|
routerURL := os.Getenv("FISSION_ROUTER_URL")
|
||||||
localRouterPort, err := util.SetupPortForward(input.Context(), opts.Client(), util.GetFissionNamespace(), "application=fission-router")
|
if len(routerURL) == 0 {
|
||||||
if err != nil {
|
// Portforward to the fission router
|
||||||
return err
|
localRouterPort, err := util.SetupPortForward(input.Context(), opts.Client(), util.GetFissionNamespace(), "application=fission-router")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
routerURL = "http://127.0.0.1:" + localRouterPort
|
||||||
}
|
}
|
||||||
fnURL := "http://127.0.0.1:" + localRouterPort + util.UrlForFunction(m.Name, m.Namespace)
|
fnURL := routerURL + util.UrlForFunction(m.Name, m.Namespace)
|
||||||
if input.IsSet(flagkey.FnSubPath) {
|
if input.IsSet(flagkey.FnSubPath) {
|
||||||
subPath := input.String(flagkey.FnSubPath)
|
subPath := input.String(flagkey.FnSubPath)
|
||||||
if !strings.HasPrefix(subPath, "/") {
|
if !strings.HasPrefix(subPath, "/") {
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ func versionHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
func (ts *HTTPTriggerSet) getRouter(fnTimeoutMap map[types.UID]int) (*mux.Router, error) {
|
func (ts *HTTPTriggerSet) getRouter(fnTimeoutMap map[types.UID]int) (*mux.Router, error) {
|
||||||
|
|
||||||
featureConfig, err := config.GetFeatureConfig()
|
featureConfig, err := config.GetFeatureConfig(ts.logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
+111
-3
@@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
|
||||||
|
v1 "github.com/fission/fission/pkg/apis/core/v1"
|
||||||
"github.com/fission/fission/test/e2e/framework"
|
"github.com/fission/fission/test/e2e/framework"
|
||||||
"github.com/fission/fission/test/e2e/framework/cli"
|
"github.com/fission/fission/test/e2e/framework/cli"
|
||||||
"github.com/fission/fission/test/e2e/framework/services"
|
"github.com/fission/fission/test/e2e/framework/services"
|
||||||
@@ -61,8 +62,10 @@ func TestFissionCLI(t *testing.T) {
|
|||||||
|
|
||||||
envName := "test-func-env"
|
envName := "test-func-env"
|
||||||
testFuncName := "hello"
|
testFuncName := "hello"
|
||||||
|
testFuncNd := "hello-nd"
|
||||||
|
testFuncCn := "hello-cn"
|
||||||
|
|
||||||
t.Run("create", func(t *testing.T) {
|
t.Run("create/poolmgr", func(t *testing.T) {
|
||||||
|
|
||||||
_, err = cli.ExecCommand(f, ctx, "env", "create", "--name", envName, "--image", "fission/python-env")
|
_, err = cli.ExecCommand(f, ctx, "env", "create", "--name", envName, "--image", "fission/python-env")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -75,9 +78,33 @@ func TestFissionCLI(t *testing.T) {
|
|||||||
require.NotNil(t, testFunc)
|
require.NotNil(t, testFunc)
|
||||||
require.Equal(t, testFuncName, testFunc.Name)
|
require.Equal(t, testFuncName, testFunc.Name)
|
||||||
require.Equal(t, envName, testFunc.Spec.Environment.Name)
|
require.Equal(t, envName, testFunc.Spec.Environment.Name)
|
||||||
|
require.Equal(t, v1.ExecutorTypePoolmgr, testFunc.Spec.InvokeStrategy.ExecutionStrategy.ExecutorType)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("update", func(t *testing.T) {
|
t.Run("create/newdeploy", func(t *testing.T) {
|
||||||
|
_, err := cli.ExecCommand(f, ctx, "function", "create", "--name", testFuncNd, "--code", "./hello.js", "--env", envName, "--executortype", "newdeploy")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
testFunc, err := fissionClient.CoreV1().Functions(metav1.NamespaceDefault).Get(ctx, testFuncNd, metav1.GetOptions{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, testFunc)
|
||||||
|
require.Equal(t, testFuncNd, testFunc.Name)
|
||||||
|
require.Equal(t, envName, testFunc.Spec.Environment.Name)
|
||||||
|
require.Equal(t, v1.ExecutorTypeNewdeploy, testFunc.Spec.InvokeStrategy.ExecutionStrategy.ExecutorType)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("create/container", func(t *testing.T) {
|
||||||
|
_, err := cli.ExecCommand(f, ctx, "function", "run-container", "--name", testFuncCn, "--image", "gcr.io/google-samples/node-hello:1.0", "--port", "8080")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
testFunc, err := fissionClient.CoreV1().Functions(metav1.NamespaceDefault).Get(ctx, testFuncCn, metav1.GetOptions{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, testFunc)
|
||||||
|
require.Equal(t, testFuncCn, testFunc.Name)
|
||||||
|
require.Equal(t, v1.ExecutorTypeContainer, testFunc.Spec.InvokeStrategy.ExecutionStrategy.ExecutorType)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("update/poolmgr", func(t *testing.T) {
|
||||||
_, err := cli.ExecCommand(f, ctx, "function", "update", "--name", testFuncName, "--labels", "env=test")
|
_, err := cli.ExecCommand(f, ctx, "function", "update", "--name", testFuncName, "--labels", "env=test")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
@@ -87,9 +114,41 @@ func TestFissionCLI(t *testing.T) {
|
|||||||
require.Equal(t, testFuncName, testFunc.Name)
|
require.Equal(t, testFuncName, testFunc.Name)
|
||||||
require.NotNil(t, testFunc.Labels)
|
require.NotNil(t, testFunc.Labels)
|
||||||
require.Equal(t, "test", testFunc.Labels["env"])
|
require.Equal(t, "test", testFunc.Labels["env"])
|
||||||
|
require.Equal(t, v1.ExecutorTypePoolmgr, testFunc.Spec.InvokeStrategy.ExecutionStrategy.ExecutorType)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("delete", func(t *testing.T) {
|
// t.Run("test/poolmgr", func(t *testing.T) {
|
||||||
|
// _, err := cli.ExecCommand(f, ctx, "function", "test", "--name", testFuncName)
|
||||||
|
// require.NoError(t, err)
|
||||||
|
// })
|
||||||
|
|
||||||
|
// t.Run("test/newdeploy", func(t *testing.T) {
|
||||||
|
// _, err := cli.ExecCommand(f, ctx, "function", "test", "--name", testFuncNd)
|
||||||
|
// require.NoError(t, err)
|
||||||
|
// })
|
||||||
|
|
||||||
|
// t.Run("test/container", func(t *testing.T) {
|
||||||
|
// _, err := cli.ExecCommand(f, ctx, "function", "test", "--name", testFuncCn)
|
||||||
|
// require.NoError(t, err)
|
||||||
|
// })
|
||||||
|
|
||||||
|
t.Run("delete/newdeploy", func(t *testing.T) {
|
||||||
|
_, err := cli.ExecCommand(f, ctx, "function", "delete", "--name", testFuncNd)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = fissionClient.CoreV1().Functions(metav1.NamespaceDefault).Get(ctx, testFuncNd, metav1.GetOptions{})
|
||||||
|
require.Error(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("delete/container", func(t *testing.T) {
|
||||||
|
_, err := cli.ExecCommand(f, ctx, "function", "delete", "--name", testFuncCn)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = fissionClient.CoreV1().Functions(metav1.NamespaceDefault).Get(ctx, testFuncCn, metav1.GetOptions{})
|
||||||
|
require.Error(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("delete/poolmgr", func(t *testing.T) {
|
||||||
_, err := cli.ExecCommand(f, ctx, "function", "delete", "--name", testFuncName)
|
_, err := cli.ExecCommand(f, ctx, "function", "delete", "--name", testFuncName)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
@@ -100,4 +159,53 @@ func TestFissionCLI(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("httptrigger", func(t *testing.T) {
|
||||||
|
|
||||||
|
t.Run("create", func(t *testing.T) {
|
||||||
|
// create env and function first
|
||||||
|
_, err := cli.ExecCommand(f, ctx, "env", "create", "--name", "test-func-env", "--image", "fission/python-env")
|
||||||
|
require.NoError(t, err)
|
||||||
|
_, err = cli.ExecCommand(f, ctx, "function", "create", "--name", "test-func", "--code", "./hello.js", "--env", "test-func-env")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = cli.ExecCommand(f, ctx, "httptrigger", "create", "--name", "test-httptrigger", "--function", "test-func", "--url", "/hello")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
ht, err := fissionClient.CoreV1().HTTPTriggers(metav1.NamespaceDefault).Get(ctx, "test-httptrigger", metav1.GetOptions{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, ht)
|
||||||
|
require.Equal(t, "test-httptrigger", ht.Name)
|
||||||
|
require.Equal(t, "test-func", ht.Spec.FunctionReference.Name)
|
||||||
|
require.Equal(t, "/hello", ht.Spec.RelativeURL)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("update", func(t *testing.T) {
|
||||||
|
_, err := cli.ExecCommand(f, ctx, "httptrigger", "update", "--name", "test-httptrigger", "--url", "/hello2")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
ht, err := fissionClient.CoreV1().HTTPTriggers(metav1.NamespaceDefault).Get(ctx, "test-httptrigger", metav1.GetOptions{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, ht)
|
||||||
|
require.Equal(t, "test-httptrigger", ht.Name)
|
||||||
|
require.Equal(t, "test-func", ht.Spec.FunctionReference.Name)
|
||||||
|
require.Equal(t, "/hello2", ht.Spec.RelativeURL)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("delete", func(t *testing.T) {
|
||||||
|
_, err := cli.ExecCommand(f, ctx, "httptrigger", "delete", "--name", "test-httptrigger")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = fissionClient.CoreV1().HTTPTriggers(metav1.NamespaceDefault).Get(ctx, "test-httptrigger", metav1.GetOptions{})
|
||||||
|
require.Error(t, err)
|
||||||
|
|
||||||
|
_, err = cli.ExecCommand(f, ctx, "function", "delete", "--name", "test-func")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = cli.ExecCommand(f, ctx, "env", "delete", "--name", "test-func-env")
|
||||||
|
require.NoError(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,18 @@ func StartServices(ctx context.Context, f *framework.Framework) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error toggling metric address: %v", err)
|
return fmt.Errorf("error toggling metric address: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// namespace settings for components
|
||||||
|
os.Setenv("FISSION_BUILDER_NAMESPACE", "")
|
||||||
|
os.Setenv("FISSION_FUNCTION_NAMESPACE", "")
|
||||||
|
os.Setenv("FISSION_DEFAULT_NAMESPACE", "default")
|
||||||
|
os.Setenv("FISSION_RESOURCE_NAMESPACES", "default")
|
||||||
|
utils.DefaultNSResolver().DefaultNamespace = "default"
|
||||||
|
utils.DefaultNSResolver().FissionResourceNS = map[string]string{
|
||||||
|
"default": "default",
|
||||||
|
}
|
||||||
|
|
||||||
|
os.Setenv("POD_READY_TIMEOUT", "300s")
|
||||||
err = executor.StartExecutor(ctx, f.ClientGen(), f.Logger(), executorPort)
|
err = executor.StartExecutor(ctx, f.ClientGen(), f.Logger(), executorPort)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error starting executor: %v", err)
|
return fmt.Errorf("error starting executor: %v", err)
|
||||||
@@ -88,5 +100,6 @@ func StartServices(ctx context.Context, f *framework.Framework) error {
|
|||||||
f.ServiceInfo["router"] = framework.ServiceInfo{
|
f.ServiceInfo["router"] = framework.ServiceInfo{
|
||||||
Port: routerPort,
|
Port: routerPort,
|
||||||
}
|
}
|
||||||
|
os.Setenv("FISSION_ROUTER_URL", fmt.Sprintf("http://localhost:%d", routerPort))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user