A newdeploy backend which uses new deployment to serve requests. This is the second phase of #193 and builds on top of changes in #384 . * Executor layer added on top of pool manager * Removed the external server for executor * Minor changes to keep existing semantics as much possible * Separating the executor vs. poolmgr backend functionality and associated data members * Executor logic separated from Poolmgr backend completely, placeholder for new backend * Changed references to poolmgr in tests * Moved poolmgr to it's package, as a side effect moved Cache to its's package (was causing cyclical dependency) and had to make some data structures exposed outside package * Rebased from master and changed references to tpr -> crd * Executor layer added on top of pool manager * Executor logic separated from Poolmgr backend completely, placeholder for new backend * Changed podName to a generic objectReference in fscache (#391) Changed podName to a generic objectReference in function service cache implementation. * Moved poolmgr to it's package, as a side effect moved Cache to its's package (was causing cyclical dependency) and had to make some data structures exposed outside package * Rebased from master and changed references to tpr -> crd * Merged from master with latest changes * Executor layer added on top of pool manager * Removed the external server for executor * Minor changes to keep existing semantics as much possible * Separating the executor vs. poolmgr backend functionality and associated data members * Executor logic separated from Poolmgr backend completely, placeholder for new backend * Changed references to poolmgr in tests * update compiling.md to use helm * Compile instructions: changed pullPolicy to IfNotPresent (#378) Containers will get stuck in ErrImagePull/ImagePullBackOff state otherwise * Moved poolmgr to it's package, as a side effect moved Cache to its's package (was causing cyclical dependency) and had to make some data structures exposed outside package * Fetcher called when pod is created for newDeploy backend but also supports older way, this is WIP and still needs pod specialization and creating & exposing a service so the URL can be hit by end user * WIP Specializing the POD as part of startup along with fetching * Working specialization of a new deployment. Needs some work on caching, cleanup etc. * Switched to service based address instead of POD address * Minor formating issue fixed * Added logging to pods and a readiness check, the readiness check is flaky though ATM * Fixed some rebase issues that were failing build * Better names for K8S objects and methods * Switched usage of FuncSvc in backends from pod to api.ObjectReference * Adding retry to fetcher request, for now just using default retry client which might need tweaking in future * Switching to plain old retry, some issue in getting retryablehttp with glide import * Removed stale executor service & deployment from previous merge * Addressed review comments, still testing some areas * Added types in FunctionSpec * Resolved conflicts due to merge from executor_abstraction branch * Added backend type on EnvironmentSpec along with operations for create/list/update, the pools are created/destroyed based on change in backend type * Backend from types and a minor err return issue fixed * Draft version of CPU and memory parameters added to environment * Added resourceReq to newDeploy, though it has some issues * Issue with resourceName fixed, now newdeploy pods also pick up resources from the environment config * Adding scale params, removing validation on CPU params for now * Fixed a formatting issue * Checking if slight more delay helps in the test which is currently failing for internal routes * The resourceList newly added in Env can not be compared by compiler, hence must use breakdown comparison instead * Added strategy selection on client side * Added caching, informers, delete operations for newdeploy backend functions * Deleted a stale directory * A simple HPA based on scale parameters, testing still WIP * Fixed a small issue in delete function, added HPA delete too when deleting a function * Previous merge missed the pkg flag for update fn command somehow, fixed that * Fixed comments from review * Changed poolmgr cleanup to be generic cleanup and moved to executor, added instanceID labels to newdeploy so that cleanup works * Moved instanceIdLabel to types to avoid cyclic dependency * More review fixes * Tweaking sleep to see results * If user does not provide poolsize, then it should not default to zero * Switched to naming convention for now, fixed default poolsize if not provided * Changed error return behaviour in delete fn, also changed cleanup to look based on obj type though support for additional type will need more work * Changed check location so avoid false logging * Test for newdeploy backend * Adding tests for poolmgr backend * Fixed an issue with glide dependency version, already fixed in master * Added instanceId for NewDeploy, Initial cleanup now cleans older objects of newdeploy backend, removed eagercreate flag and instead using minScale to drive eager creation * Moved cleanup to executor layer with cleanup for newDeploy backend, changes to use the new Cache impl * Cleaning up pod & rs along with deployment for newdeploy backend * Enhanced fn and env listing to show min/maxscale and resuorces respectively * Added conditional heapster deployment and fixed a small issue with resources for fetcher container in function pod * Addressed review comments from previous change * Addressed some more review comments - majorly create only on NotFoundError * Added TargetCPU as an input for scaling * Bumped target CPU to be greater than 0 and added a default value * Min replicas should be 1 even if the minScale is 0 when creating deployment * Changed name from 'backend' to executorType, added additional test for minscale 0 case, changed TargetCPU to TargetCPUPercent
231 lines
5.7 KiB
Go
231 lines
5.7 KiB
Go
/*
|
|
Copyright 2016 The Fission Authors.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package fscache
|
|
|
|
import (
|
|
"log"
|
|
"time"
|
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/client-go/pkg/api"
|
|
|
|
"github.com/fission/fission"
|
|
"github.com/fission/fission/cache"
|
|
"github.com/fission/fission/crd"
|
|
)
|
|
|
|
type fscRequestType int
|
|
type executorType int
|
|
|
|
const (
|
|
TOUCH fscRequestType = iota
|
|
LISTOLD
|
|
LOG
|
|
)
|
|
|
|
const (
|
|
POOLMGR executorType = iota
|
|
NEWDEPLOY
|
|
)
|
|
|
|
type (
|
|
FuncSvc struct {
|
|
Name string // Name of object
|
|
Function *metav1.ObjectMeta // function this pod/service is for
|
|
Environment *crd.Environment // function's environment
|
|
Address string // Host:Port or IP:Port that the function's service can be reached at.
|
|
KubernetesObjects []api.ObjectReference // Kubernetes Objects (within the function namespace)
|
|
Executor executorType
|
|
|
|
Ctime time.Time
|
|
Atime time.Time
|
|
}
|
|
|
|
FunctionServiceCache struct {
|
|
byFunction *cache.Cache // function-key -> funcSvc : map[string]*funcSvc
|
|
byAddress *cache.Cache // address -> function : map[string]metav1.ObjectMeta
|
|
|
|
requestChannel chan *fscRequest
|
|
}
|
|
fscRequest struct {
|
|
requestType fscRequestType
|
|
address string
|
|
kubernetesObjects []api.ObjectReference
|
|
age time.Duration
|
|
env *metav1.ObjectMeta // used for ListOld
|
|
responseChannel chan *fscResponse
|
|
}
|
|
fscResponse struct {
|
|
objects []*FuncSvc
|
|
deleted bool
|
|
error
|
|
}
|
|
)
|
|
|
|
func MakeFunctionServiceCache() *FunctionServiceCache {
|
|
fsc := &FunctionServiceCache{
|
|
byFunction: cache.MakeCache(0, 0),
|
|
byAddress: cache.MakeCache(0, 0),
|
|
requestChannel: make(chan *fscRequest),
|
|
}
|
|
go fsc.service()
|
|
return fsc
|
|
}
|
|
|
|
func (fsc *FunctionServiceCache) service() {
|
|
for {
|
|
req := <-fsc.requestChannel
|
|
resp := &fscResponse{}
|
|
switch req.requestType {
|
|
case TOUCH:
|
|
// update atime for this function svc
|
|
resp.error = fsc._touchByAddress(req.address)
|
|
case LISTOLD:
|
|
// get svcs idle for > req.age
|
|
fscs := fsc.byFunction.Copy()
|
|
funcObjects := make([]*FuncSvc, 0)
|
|
for _, funcSvc := range fscs {
|
|
fsvc := funcSvc.(*FuncSvc)
|
|
if fsvc.Environment.Metadata.UID == req.env.UID &&
|
|
time.Since(fsvc.Atime) > req.age {
|
|
funcObjects = append(funcObjects, fsvc)
|
|
}
|
|
}
|
|
resp.objects = funcObjects
|
|
case LOG:
|
|
funcCopy := fsc.byFunction.Copy()
|
|
log.Printf("Cache has %v entries", len(funcCopy))
|
|
for key, fsvcI := range funcCopy {
|
|
fsvc := fsvcI.(*FuncSvc)
|
|
for _, kubeObj := range fsvc.KubernetesObjects {
|
|
log.Printf("%v\t%v\t%v", key, kubeObj.Kind, kubeObj.Name)
|
|
}
|
|
}
|
|
}
|
|
req.responseChannel <- resp
|
|
}
|
|
}
|
|
|
|
func (fsc *FunctionServiceCache) GetByFunction(m *metav1.ObjectMeta) (*FuncSvc, error) {
|
|
key := crd.CacheKey(m)
|
|
|
|
fsvcI, err := fsc.byFunction.Get(key)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// update atime
|
|
fsvc := fsvcI.(*FuncSvc)
|
|
fsvc.Atime = time.Now()
|
|
|
|
fsvcCopy := *fsvc
|
|
return &fsvcCopy, nil
|
|
}
|
|
|
|
func (fsc *FunctionServiceCache) Add(fsvc FuncSvc) (*FuncSvc, error) {
|
|
err, existing := fsc.byFunction.Set(crd.CacheKey(fsvc.Function), &fsvc)
|
|
if err != nil {
|
|
if existing != nil {
|
|
f := existing.(*FuncSvc)
|
|
err2 := fsc.TouchByAddress(f.Address)
|
|
if err2 != nil {
|
|
return nil, err2
|
|
}
|
|
fCopy := *f
|
|
return &fCopy, err
|
|
}
|
|
return nil, err
|
|
}
|
|
now := time.Now()
|
|
fsvc.Ctime = now
|
|
fsvc.Atime = now
|
|
|
|
// Add to byAddress cache. Ignore NameExists errors
|
|
// because of multiple-specialization. See issue #331.
|
|
err, _ = fsc.byAddress.Set(fsvc.Address, *fsvc.Function)
|
|
if err != nil {
|
|
if fe, ok := err.(fission.Error); ok {
|
|
if fe.Code == fission.ErrorNameExists {
|
|
err = nil
|
|
}
|
|
}
|
|
log.Printf("error caching fsvc: %v", err)
|
|
return nil, err
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
func (fsc *FunctionServiceCache) TouchByAddress(address string) error {
|
|
responseChannel := make(chan *fscResponse)
|
|
fsc.requestChannel <- &fscRequest{
|
|
requestType: TOUCH,
|
|
address: address,
|
|
responseChannel: responseChannel,
|
|
}
|
|
resp := <-responseChannel
|
|
return resp.error
|
|
}
|
|
|
|
func (fsc *FunctionServiceCache) _touchByAddress(address string) error {
|
|
mI, err := fsc.byAddress.Get(address)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
m := mI.(metav1.ObjectMeta)
|
|
fsvcI, err := fsc.byFunction.Get(crd.CacheKey(&m))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
fsvc := fsvcI.(*FuncSvc)
|
|
fsvc.Atime = time.Now()
|
|
return nil
|
|
}
|
|
|
|
func (fsc *FunctionServiceCache) DeleteOld(fsvc *FuncSvc, minAge time.Duration) (bool, error) {
|
|
if time.Since(fsvc.Atime) < minAge {
|
|
return false, nil
|
|
}
|
|
|
|
fsc.byFunction.Delete(crd.CacheKey(fsvc.Function))
|
|
fsc.byAddress.Delete(fsvc.Address)
|
|
|
|
return true, nil
|
|
}
|
|
|
|
func (fsc *FunctionServiceCache) ListOld(env *metav1.ObjectMeta, age time.Duration) ([]*FuncSvc, error) {
|
|
responseChannel := make(chan *fscResponse)
|
|
fsc.requestChannel <- &fscRequest{
|
|
requestType: LISTOLD,
|
|
age: age,
|
|
env: env,
|
|
responseChannel: responseChannel,
|
|
}
|
|
resp := <-responseChannel
|
|
return resp.objects, resp.error
|
|
}
|
|
|
|
func (fsc *FunctionServiceCache) Log() {
|
|
log.Printf("--- FunctionService Cache Contents")
|
|
responseChannel := make(chan *fscResponse)
|
|
fsc.requestChannel <- &fscRequest{
|
|
requestType: LOG,
|
|
responseChannel: responseChannel,
|
|
}
|
|
<-responseChannel
|
|
log.Printf("--- FunctionService Cache Contents End")
|
|
}
|