Executor: Dump function service cache for pool manager functions (#2789)
* dump function service cache for executor * fix lint issue * code refactor and lint fixes --------- Signed-off-by: Shubham Bansal <shubhambansaliimtgn@gmail.com> Signed-off-by: Sanket Sudake <sanketsudake@gmail.com> Co-authored-by: Sanket Sudake <sanketsudake@gmail.com>
This commit is contained in:
co-authored by
Sanket Sudake
parent
6c431e4d9b
commit
f99f10134c
@@ -263,6 +263,19 @@ func (executor *Executor) unTapService(w http.ResponseWriter, r *http.Request) {
|
|||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// dumpDebugInfo => dump function service for pool cache
|
||||||
|
func (executor *Executor) dumpDebugInfo(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// currently we are considering dumping function only for pool manager
|
||||||
|
et := executor.executorTypes[fv1.ExecutorTypePoolmgr]
|
||||||
|
if err := et.DumpDebugInfo(r.Context()); err != nil {
|
||||||
|
code, msg := ferror.GetHTTPError(err)
|
||||||
|
http.Error(w, msg, code)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
// GetHandler returns an http.Handler.
|
// GetHandler returns an http.Handler.
|
||||||
func (executor *Executor) GetHandler() http.Handler {
|
func (executor *Executor) GetHandler() http.Handler {
|
||||||
r := mux.NewRouter()
|
r := mux.NewRouter()
|
||||||
@@ -272,6 +285,7 @@ func (executor *Executor) GetHandler() http.Handler {
|
|||||||
r.HandleFunc("/v2/tapServices", executor.tapServices).Methods("POST")
|
r.HandleFunc("/v2/tapServices", executor.tapServices).Methods("POST")
|
||||||
r.HandleFunc("/healthz", executor.healthHandler).Methods("GET")
|
r.HandleFunc("/healthz", executor.healthHandler).Methods("GET")
|
||||||
r.HandleFunc("/v2/unTapService", executor.unTapService).Methods("POST")
|
r.HandleFunc("/v2/unTapService", executor.unTapService).Methods("POST")
|
||||||
|
r.HandleFunc("/v2/debugInfo", executor.dumpDebugInfo).Methods("GET")
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -787,3 +787,7 @@ func getDeploymentObj(kubeobjs []apiv1.ObjectReference) *apiv1.ObjectReference {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (caaf *Container) DumpDebugInfo(ctx context.Context) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -38,6 +38,9 @@ type ExecutorType interface {
|
|||||||
// GetFuncSvcFromCache retrieves function service from cache.
|
// GetFuncSvcFromCache retrieves function service from cache.
|
||||||
GetFuncSvcFromCache(context.Context, *fv1.Function) (*fscache.FuncSvc, error)
|
GetFuncSvcFromCache(context.Context, *fv1.Function) (*fscache.FuncSvc, error)
|
||||||
|
|
||||||
|
// DumpDebugInfo dump function service cache to temporary directory of executor pod.
|
||||||
|
DumpDebugInfo(context.Context) error
|
||||||
|
|
||||||
// DeleteFuncSvcFromCache deletes function service entry in cache.
|
// DeleteFuncSvcFromCache deletes function service entry in cache.
|
||||||
DeleteFuncSvcFromCache(context.Context, *fscache.FuncSvc)
|
DeleteFuncSvcFromCache(context.Context, *fscache.FuncSvc)
|
||||||
|
|
||||||
|
|||||||
@@ -889,3 +889,7 @@ func (deploy *NewDeploy) scaleDeployment(ctx context.Context, deplNS string, dep
|
|||||||
}, metav1.UpdateOptions{})
|
}, metav1.UpdateOptions{})
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (deploy *NewDeploy) DumpDebugInfo(ctx context.Context) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -762,3 +762,7 @@ func (gpm *GenericPoolManager) NoActiveConnectionEventChecker(ctx context.Contex
|
|||||||
}
|
}
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (gpm *GenericPoolManager) DumpDebugInfo(ctx context.Context) error {
|
||||||
|
return gpm.fsCache.DumpDebugInfo(ctx)
|
||||||
|
}
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import (
|
|||||||
"github.com/fission/fission/pkg/crd"
|
"github.com/fission/fission/pkg/crd"
|
||||||
ferror "github.com/fission/fission/pkg/error"
|
ferror "github.com/fission/fission/pkg/error"
|
||||||
"github.com/fission/fission/pkg/executor/metrics"
|
"github.com/fission/fission/pkg/executor/metrics"
|
||||||
|
"github.com/fission/fission/pkg/executor/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
type fscRequestType int
|
type fscRequestType int
|
||||||
@@ -170,6 +171,27 @@ func (fsc *FunctionServiceCache) service() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DumpDebugInfo => dump function service cache data to temporary directory of executor pod.
|
||||||
|
func (fsc *FunctionServiceCache) DumpDebugInfo(ctx context.Context) error {
|
||||||
|
fsc.logger.Info("dumping function service")
|
||||||
|
|
||||||
|
file, err := util.CreateDumpFile(fsc.logger)
|
||||||
|
if err != nil {
|
||||||
|
fsc.logger.Error("error while creating file/dir", zap.String("error", err.Error()))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
err = fsc.connFunctionCache.LogFnSvcGroup(ctx, file)
|
||||||
|
if err != nil {
|
||||||
|
fsc.logger.Error("error while logging function service group", zap.String("error", err.Error()))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fsc.logger.Info("dumped function service")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetByFunction gets a function service from cache using function key.
|
// GetByFunction gets a function service from cache using function key.
|
||||||
func (fsc *FunctionServiceCache) GetByFunction(m *metav1.ObjectMeta) (*FuncSvc, error) {
|
func (fsc *FunctionServiceCache) GetByFunction(m *metav1.ObjectMeta) (*FuncSvc, error) {
|
||||||
key := crd.CacheKey(m)
|
key := crd.CacheKey(m)
|
||||||
|
|||||||
@@ -17,8 +17,10 @@ limitations under the License.
|
|||||||
package fscache
|
package fscache
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"k8s.io/apimachinery/pkg/api/resource"
|
"k8s.io/apimachinery/pkg/api/resource"
|
||||||
@@ -37,6 +39,7 @@ const (
|
|||||||
deleteValue
|
deleteValue
|
||||||
setCPUUtilization
|
setCPUUtilization
|
||||||
markSpecializationFailure
|
markSpecializationFailure
|
||||||
|
logFuncSvc
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
@@ -66,6 +69,7 @@ type (
|
|||||||
ctx context.Context
|
ctx context.Context
|
||||||
function string
|
function string
|
||||||
address string
|
address string
|
||||||
|
dumpWriter io.Writer
|
||||||
value *FuncSvc
|
value *FuncSvc
|
||||||
requestsPerPod int
|
requestsPerPod int
|
||||||
cpuUsage resource.Quantity
|
cpuUsage resource.Quantity
|
||||||
@@ -244,6 +248,48 @@ func (c *PoolCache) service() {
|
|||||||
case deleteValue:
|
case deleteValue:
|
||||||
delete(c.cache[req.function].svcs, req.address)
|
delete(c.cache[req.function].svcs, req.address)
|
||||||
req.responseChannel <- resp
|
req.responseChannel <- resp
|
||||||
|
case logFuncSvc:
|
||||||
|
datawriter := bufio.NewWriter(req.dumpWriter)
|
||||||
|
|
||||||
|
writefnSvcGrp := func(svcGrp *funcSvcGroup) error {
|
||||||
|
_, err := datawriter.WriteString(fmt.Sprintf("svc_waiting:%d\tqueue_len:%d", svcGrp.svcWaiting, svcGrp.queue.Len()))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(svcGrp.svcs) == 0 {
|
||||||
|
_, err := datawriter.WriteString("\n")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for addr, fnSvc := range svcGrp.svcs {
|
||||||
|
_, err := datawriter.WriteString(fmt.Sprintf("\tfunction_name:%s\tfn_svc_address:%s\tactive_req:%d\tcurrent_cpu_usage:%v\tcpu_limit:%v\n",
|
||||||
|
fnSvc.val.Function.Name, addr, fnSvc.activeRequests, fnSvc.currentCPUUsage, fnSvc.cpuLimit))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, fnSvcGrp := range c.cache {
|
||||||
|
err := writefnSvcGrp(fnSvcGrp)
|
||||||
|
if err != nil {
|
||||||
|
resp.error = err
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err := datawriter.Flush()
|
||||||
|
if err != nil {
|
||||||
|
if resp.error == nil {
|
||||||
|
resp.error = err
|
||||||
|
} else {
|
||||||
|
resp.error = fmt.Errorf("%v, %v", resp.error, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
req.responseChannel <- resp
|
||||||
default:
|
default:
|
||||||
resp.error = ferror.MakeError(ferror.ErrorInvalidArgument,
|
resp.error = ferror.MakeError(ferror.ErrorInvalidArgument,
|
||||||
fmt.Sprintf("invalid request type: %v", req.requestType))
|
fmt.Sprintf("invalid request type: %v", req.requestType))
|
||||||
@@ -346,3 +392,14 @@ func (c *PoolCache) MarkSpecializationFailure(function string) {
|
|||||||
responseChannel: make(chan *response),
|
responseChannel: make(chan *response),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *PoolCache) LogFnSvcGroup(ctx context.Context, file io.Writer) error {
|
||||||
|
respChannel := make(chan *response)
|
||||||
|
c.requestChannel <- &request{
|
||||||
|
requestType: logFuncSvc,
|
||||||
|
dumpWriter: file,
|
||||||
|
responseChannel: respChannel,
|
||||||
|
}
|
||||||
|
resp := <-respChannel
|
||||||
|
return resp.error
|
||||||
|
}
|
||||||
|
|||||||
@@ -35,6 +35,10 @@ import (
|
|||||||
"github.com/fission/fission/pkg/utils"
|
"github.com/fission/fission/pkg/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
dumpFileName string = "fission-dump"
|
||||||
|
)
|
||||||
|
|
||||||
// ApplyImagePullSecret applies image pull secret to the give pod spec.
|
// ApplyImagePullSecret applies image pull secret to the give pod spec.
|
||||||
// It's intentional not to check the existence of secret here.
|
// It's intentional not to check the existence of secret here.
|
||||||
// First, Kubernetes will set Pod status to "ImagePullBackOff" once
|
// First, Kubernetes will set Pod status to "ImagePullBackOff" once
|
||||||
@@ -152,3 +156,11 @@ func GetObjectReaperInterval(logger *zap.Logger, executorType fv1.ExecutorType,
|
|||||||
func getExecutorEnvVarName(executor fv1.ExecutorType) string {
|
func getExecutorEnvVarName(executor fv1.ExecutorType) string {
|
||||||
return strings.ToUpper(string(executor)) + "_OBJECT_REAPER_INTERVAL"
|
return strings.ToUpper(string(executor)) + "_OBJECT_REAPER_INTERVAL"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreateDumpFile => create dump file inside temp directory
|
||||||
|
func CreateDumpFile(logger *zap.Logger) (*os.File, error) {
|
||||||
|
dumpPath := os.TempDir()
|
||||||
|
logger.Info("creating dump file", zap.String("dump_path", dumpPath))
|
||||||
|
|
||||||
|
return os.Create(fmt.Sprintf("%s/%s-%d.txt", dumpPath, dumpFileName, time.Now().Unix()))
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user