Changed podName to a generic objectReference in fscache (#391)

Changed podName to a generic objectReference in function service cache implementation.
This commit is contained in:
Vishal
2017-11-15 13:57:19 -08:00
committed by Soam Vasani
parent 8a097abf9b
commit 7bb397dfee
3 changed files with 86 additions and 61 deletions
+47 -39
View File
@@ -21,6 +21,7 @@ import (
"time" "time"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/pkg/api"
"github.com/fission/fission" "github.com/fission/fission"
"github.com/fission/fission/cache" "github.com/fission/fission/cache"
@@ -28,43 +29,50 @@ import (
) )
type fscRequestType int type fscRequestType int
type backendType int
const ( const (
TOUCH fscRequestType = iota TOUCH fscRequestType = iota
LISTOLD LISTOLD
LOG LOG
DELETE_BY_POD DELETE_BY_OBJECT
)
const (
POOLMGR backendType = iota
NEWDEPLOY
) )
type ( type (
funcSvc struct { funcSvc struct {
function *metav1.ObjectMeta // function this pod/service is for function *metav1.ObjectMeta // function this pod/service is for
environment *crd.Environment // function's environment environment *crd.Environment // function's environment
address string // Host:Port or IP:Port that the function's service can be reached at. address string // Host:Port or IP:Port that the function's service can be reached at.
podName string // pod name (within the function namespace) kubernetesObject api.ObjectReference // Kubernetes Object (within the function namespace)
backend backendType
ctime time.Time ctime time.Time
atime time.Time atime time.Time
} }
functionServiceCache struct { functionServiceCache struct {
byFunction *cache.Cache // function-key -> funcSvc : map[string]*funcSvc byFunction *cache.Cache // function-key -> funcSvc : map[string]*funcSvc
byAddress *cache.Cache // address -> function : map[string]metav1.ObjectMeta byAddress *cache.Cache // address -> function : map[string]metav1.ObjectMeta
byPod *cache.Cache // podname -> function : map[string]metav1.ObjectMeta byKubeObject *cache.Cache // obj -> function : map[api.ObjectReference]metav1.ObjectMeta
requestChannel chan *fscRequest requestChannel chan *fscRequest
} }
fscRequest struct { fscRequest struct {
requestType fscRequestType requestType fscRequestType
address string address string
podName string kubernetesObject api.ObjectReference
age time.Duration age time.Duration
env *metav1.ObjectMeta // used for ListOld env *metav1.ObjectMeta // used for ListOld
responseChannel chan *fscResponse responseChannel chan *fscResponse
} }
fscResponse struct { fscResponse struct {
podNames []string objects []api.ObjectReference
deleted bool deleted bool
error error
} }
) )
@@ -73,7 +81,7 @@ func MakeFunctionServiceCache() *functionServiceCache {
fsc := &functionServiceCache{ fsc := &functionServiceCache{
byFunction: cache.MakeCache(0, 0), byFunction: cache.MakeCache(0, 0),
byAddress: cache.MakeCache(0, 0), byAddress: cache.MakeCache(0, 0),
byPod: cache.MakeCache(0, 0), byKubeObject: cache.MakeCache(0, 0),
requestChannel: make(chan *fscRequest), requestChannel: make(chan *fscRequest),
} }
go fsc.service() go fsc.service()
@@ -90,9 +98,9 @@ func (fsc *functionServiceCache) service() {
resp.error = fsc._touchByAddress(req.address) resp.error = fsc._touchByAddress(req.address)
case LISTOLD: case LISTOLD:
// get svcs idle for > req.age // get svcs idle for > req.age
byPodCopy := fsc.byPod.Copy() byKubeObjectCopy := fsc.byKubeObject.Copy()
pods := make([]string, 0) kubeObjects := make([]api.ObjectReference, 0)
for podNameI, mI := range byPodCopy { for objI, mI := range byKubeObjectCopy {
m := mI.(metav1.ObjectMeta) m := mI.(metav1.ObjectMeta)
fsvcI, err := fsc.byFunction.Get(crd.CacheKey(&m)) fsvcI, err := fsc.byFunction.Get(crd.CacheKey(&m))
if err != nil { if err != nil {
@@ -102,21 +110,21 @@ func (fsc *functionServiceCache) service() {
if fsvc.environment.Metadata.UID == req.env.UID && if fsvc.environment.Metadata.UID == req.env.UID &&
time.Now().Sub(fsvc.atime) > req.age { time.Now().Sub(fsvc.atime) > req.age {
podName := podNameI.(string) obj := objI.(api.ObjectReference)
pods = append(pods, podName) kubeObjects = append(kubeObjects, obj)
} }
} }
} }
resp.podNames = pods resp.objects = kubeObjects
case LOG: case LOG:
funcCopy := fsc.byFunction.Copy() funcCopy := fsc.byFunction.Copy()
log.Printf("Cache has %v entries", len(funcCopy)) log.Printf("Cache has %v entries", len(funcCopy))
for key, fsvcI := range funcCopy { for key, fsvcI := range funcCopy {
fsvc := fsvcI.(*funcSvc) fsvc := fsvcI.(*funcSvc)
log.Printf("%v\t%v", key, fsvc.podName) log.Printf("%v\t%v\t%v", key, fsvc.kubernetesObject.Kind, fsvc.kubernetesObject.Name)
} }
case DELETE_BY_POD: case DELETE_BY_OBJECT:
resp.deleted, resp.error = fsc._deleteByPod(req.podName, req.age) resp.deleted, resp.error = fsc._deleteByKubeObject(req.kubernetesObject, req.age)
} }
req.responseChannel <- resp req.responseChannel <- resp
} }
@@ -157,7 +165,7 @@ func (fsc *functionServiceCache) Add(fsvc funcSvc) (error, *funcSvc) {
fsvc.ctime = now fsvc.ctime = now
fsvc.atime = now fsvc.atime = now
// Add to byAddress and byPod caches. Ignore NameExists errors // Add to byAddress and byKubernetesObject caches. Ignore NameExists errors
// because of multiple-specialization. See issue #331. // because of multiple-specialization. See issue #331.
err, _ = fsc.byAddress.Set(fsvc.address, *fsvc.function) err, _ = fsc.byAddress.Set(fsvc.address, *fsvc.function)
if err != nil { if err != nil {
@@ -169,7 +177,7 @@ func (fsc *functionServiceCache) Add(fsvc funcSvc) (error, *funcSvc) {
log.Printf("error caching fsvc: %v", err) log.Printf("error caching fsvc: %v", err)
return err, nil return err, nil
} }
err, _ = fsc.byPod.Set(fsvc.podName, *fsvc.function) err, _ = fsc.byKubeObject.Set(fsvc.kubernetesObject, *fsvc.function)
if err != nil { if err != nil {
if fe, ok := err.(fission.Error); ok { if fe, ok := err.(fission.Error); ok {
if fe.Code == fission.ErrorNameExists { if fe.Code == fission.ErrorNameExists {
@@ -208,22 +216,22 @@ func (fsc *functionServiceCache) _touchByAddress(address string) error {
return nil return nil
} }
func (fsc *functionServiceCache) DeleteByPod(podName string, minAge time.Duration) (bool, error) { func (fsc *functionServiceCache) DeleteByKubeObject(obj api.ObjectReference, minAge time.Duration) (bool, error) {
responseChannel := make(chan *fscResponse) responseChannel := make(chan *fscResponse)
fsc.requestChannel <- &fscRequest{ fsc.requestChannel <- &fscRequest{
requestType: DELETE_BY_POD, requestType: DELETE_BY_OBJECT,
podName: podName, kubernetesObject: obj,
age: minAge, age: minAge,
responseChannel: responseChannel, responseChannel: responseChannel,
} }
resp := <-responseChannel resp := <-responseChannel
return resp.deleted, resp.error return resp.deleted, resp.error
} }
// _deleteByPod deletes the entry keyed by podName, but only if it is // _deleteByKubeObject deletes the entry keyed by Kubernetes Object, but only if it is
// at least minAge old. // at least minAge old.
func (fsc *functionServiceCache) _deleteByPod(podName string, minAge time.Duration) (bool, error) { func (fsc *functionServiceCache) _deleteByKubeObject(obj api.ObjectReference, minAge time.Duration) (bool, error) {
mI, err := fsc.byPod.Get(podName) mI, err := fsc.byKubeObject.Get(obj)
if err != nil { if err != nil {
return false, err return false, err
} }
@@ -240,11 +248,11 @@ func (fsc *functionServiceCache) _deleteByPod(podName string, minAge time.Durati
fsc.byFunction.Delete(crd.CacheKey(&m)) fsc.byFunction.Delete(crd.CacheKey(&m))
fsc.byAddress.Delete(fsvc.address) fsc.byAddress.Delete(fsvc.address)
fsc.byPod.Delete(podName) fsc.byKubeObject.Delete(obj)
return true, nil return true, nil
} }
func (fsc *functionServiceCache) ListOld(env *metav1.ObjectMeta, age time.Duration) ([]string, error) { func (fsc *functionServiceCache) ListOld(env *metav1.ObjectMeta, age time.Duration) ([]api.ObjectReference, error) {
responseChannel := make(chan *fscResponse) responseChannel := make(chan *fscResponse)
fsc.requestChannel <- &fscRequest{ fsc.requestChannel <- &fscRequest{
requestType: LISTOLD, requestType: LISTOLD,
@@ -253,7 +261,7 @@ func (fsc *functionServiceCache) ListOld(env *metav1.ObjectMeta, age time.Durati
responseChannel: responseChannel, responseChannel: responseChannel,
} }
resp := <-responseChannel resp := <-responseChannel
return resp.podNames, resp.error return resp.objects, resp.error
} }
func (fsc *functionServiceCache) Log() { func (fsc *functionServiceCache) Log() {
+10 -4
View File
@@ -6,6 +6,7 @@ import (
"time" "time"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/pkg/api"
"github.com/fission/fission" "github.com/fission/fission"
"github.com/fission/fission/crd" "github.com/fission/fission/crd"
@@ -39,9 +40,14 @@ func TestFunctionServiceCache(t *testing.T) {
}, },
}, },
address: "xxx", address: "xxx",
podName: "yyy", kubernetesObject: api.ObjectReference{
ctime: now, Kind: "pod",
atime: now, Name: "xxx",
APIVersion: "v1",
Namespace: "fission-function",
},
ctime: now,
atime: now,
} }
err, _ := fsc.Add(*fsvc) err, _ := fsc.Add(*fsvc)
if err != nil { if err != nil {
@@ -67,7 +73,7 @@ func TestFunctionServiceCache(t *testing.T) {
log.Panicf("Failed to touch fsvc: %v", err) log.Panicf("Failed to touch fsvc: %v", err)
} }
deleted, err := fsc.DeleteByPod(fsvc.podName, 0) deleted, err := fsc.DeleteByKubeObject(fsvc.kubernetesObject, 0)
if err != nil { if err != nil {
fsc.Log() fsc.Log()
log.Panicf("Failed to delete fsvc: %v", err) log.Panicf("Failed to delete fsvc: %v", err)
+29 -18
View File
@@ -36,6 +36,7 @@ import (
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/util/intstr" "k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes"
"k8s.io/client-go/pkg/api"
apiv1 "k8s.io/client-go/pkg/api/v1" apiv1 "k8s.io/client-go/pkg/api/v1"
"k8s.io/client-go/pkg/apis/extensions/v1beta1" "k8s.io/client-go/pkg/apis/extensions/v1beta1"
@@ -556,13 +557,23 @@ func (gp *GenericPool) GetFuncSvc(m *metav1.ObjectMeta) (*funcSvc, error) {
svcHost = fmt.Sprintf("%v:8888", pod.Status.PodIP) svcHost = fmt.Sprintf("%v:8888", pod.Status.PodIP)
} }
kubeObjRef := api.ObjectReference{
Kind: pod.TypeMeta.Kind,
Name: pod.ObjectMeta.Name,
APIVersion: pod.TypeMeta.APIVersion,
Namespace: pod.ObjectMeta.Namespace,
ResourceVersion: pod.ObjectMeta.ResourceVersion,
UID: pod.ObjectMeta.UID,
}
fsvc := &funcSvc{ fsvc := &funcSvc{
function: m, function: m,
environment: gp.env, environment: gp.env,
address: svcHost, address: svcHost,
podName: pod.ObjectMeta.Name, kubernetesObject: kubeObjRef,
ctime: time.Now(), backend: POOLMGR,
atime: time.Now(), ctime: time.Now(),
atime: time.Now(),
} }
err, existingFsvc := gp.fsCache.Add(*fsvc) err, existingFsvc := gp.fsCache.Add(*fsvc)
@@ -571,9 +582,9 @@ func (gp *GenericPool) GetFuncSvc(m *metav1.ObjectMeta) (*funcSvc, error) {
if fe.Code == fission.ErrorNameExists { if fe.Code == fission.ErrorNameExists {
// Some other thread beat us to it -- return the other thread's fsvc and clean up // Some other thread beat us to it -- return the other thread's fsvc and clean up
// our own. // our own.
log.Printf("func svc already exists: %v", existingFsvc.podName) log.Printf("func svc already exists: %v", existingFsvc.kubernetesObject.Name)
go func() { go func() {
gp.kubernetesClient.CoreV1().Pods(gp.namespace).Delete(fsvc.podName, nil) gp.kubernetesClient.CoreV1().Pods(gp.namespace).Delete(fsvc.kubernetesObject.Name, nil)
}() }()
return existingFsvc, nil return existingFsvc, nil
} }
@@ -583,19 +594,19 @@ func (gp *GenericPool) GetFuncSvc(m *metav1.ObjectMeta) (*funcSvc, error) {
return fsvc, nil return fsvc, nil
} }
func (gp *GenericPool) CleanupFunctionService(podName string) error { func (gp *GenericPool) CleanupFunctionService(obj api.ObjectReference) error {
// remove ourselves from fsCache (only if we're still old) // remove ourselves from fsCache (only if we're still old)
deleted, err := gp.fsCache.DeleteByPod(podName, gp.idlePodReapTime) deleted, err := gp.fsCache.DeleteByKubeObject(obj, gp.idlePodReapTime)
if err != nil { if err != nil {
return err return err
} }
if !deleted { if !deleted {
log.Printf("Not deleting %v, in use", podName) log.Printf("Not deleting %v, in use", obj.Name)
return nil return nil
} }
pod, err := gp.kubernetesClient.CoreV1().Pods(gp.namespace).Get(podName, metav1.GetOptions{}) pod, err := gp.kubernetesClient.CoreV1().Pods(gp.namespace).Get(obj.Name, metav1.GetOptions{})
if err != nil { if err != nil {
return err return err
} }
@@ -613,7 +624,7 @@ func (gp *GenericPool) CleanupFunctionService(podName string) error {
} }
// delete pod // delete pod
err = gp.kubernetesClient.CoreV1().Pods(gp.namespace).Delete(podName, nil) err = gp.kubernetesClient.CoreV1().Pods(gp.namespace).Delete(obj.Name, nil)
if err != nil { if err != nil {
return err return err
} }
@@ -624,16 +635,16 @@ func (gp *GenericPool) CleanupFunctionService(podName string) error {
func (gp *GenericPool) idlePodReaper() { func (gp *GenericPool) idlePodReaper() {
for { for {
time.Sleep(time.Minute) time.Sleep(time.Minute)
podNames, err := gp.fsCache.ListOld(&gp.env.Metadata, gp.idlePodReapTime) objects, err := gp.fsCache.ListOld(&gp.env.Metadata, gp.idlePodReapTime)
if err != nil { if err != nil {
log.Printf("Error reaping idle pods: %v", err) log.Printf("Error reaping idle pods: %v", err)
continue continue
} }
for _, podName := range podNames { for _, obj := range objects {
log.Printf("Reaping idle pod '%v'", podName) log.Printf("Reaping idle pod '%v'", obj.Name)
err := gp.CleanupFunctionService(podName) err := gp.CleanupFunctionService(obj)
if err != nil { if err != nil {
log.Printf("Error deleting idle pod '%v': %v", podName, err) log.Printf("Error deleting idle pod '%v': %v", obj.Name, err)
} }
} }
} }