Files
fission-src/poolmgr/api.go
T
Soam Vasani f8a1fdf4c6 Improve logging in controller, fetcher, poolmgr
TODO: most of these should be in a debug loglevel.
2016-11-02 15:06:55 -07:00

168 lines
4.2 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 poolmgr
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"time"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
"github.com/platform9/fission"
"github.com/platform9/fission/cache"
controllerclient "github.com/platform9/fission/controller/client"
)
type funcSvc struct {
function *fission.Metadata // function this thing is for
environment *fission.Environment // env it was obtained from
serviceName string // name of k8s svc
ctime time.Time
atime time.Time
}
type API struct {
poolMgr *GenericPoolManager
functionEnv *cache.Cache // map[fission.Metadata]fission.Environment
functionService *cache.Cache // map[fission.Metadata]funcSvc
controller *controllerclient.Client
}
func MakeAPI(gpm *GenericPoolManager, controller *controllerclient.Client) *API {
return &API{
poolMgr: gpm,
functionEnv: cache.MakeCache(),
functionService: cache.MakeCache(),
controller: controller,
}
}
func (api *API) getServiceForFunctionApi(w http.ResponseWriter, r *http.Request) {
body, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, "Failed to read request", 500)
return
}
// get function metadata
m := fission.Metadata{}
err = json.Unmarshal(body, &m)
if err != nil {
http.Error(w, "Failed to parse request", 400)
return
}
serviceName, err := api.getServiceForFunction(&m)
if err != nil {
code, msg := fission.GetHTTPError(err)
log.Printf("Error: %v: %v", code, msg)
http.Error(w, msg, code)
}
w.Write([]byte(serviceName))
}
func (api *API) getFunctionEnv(m *fission.Metadata) (*fission.Environment, error) {
var env *fission.Environment
// Cached ?
result, err := api.functionEnv.Get(m)
if err == nil {
env = result.(*fission.Environment)
return env, nil
}
// Cache miss -- get func from controller
log.Printf("[%v] getting function from controller", m)
f, err := api.controller.FunctionGet(m)
if err != nil {
return nil, err
}
// Get env from metadata
log.Printf("[%v] getting env from controller", m)
env, err = api.controller.EnvironmentGet(&f.Environment)
if err != nil {
return nil, err
}
// cache for future
api.functionEnv.Set(m, env)
return env, nil
}
func (api *API) getServiceForFunction(m *fission.Metadata) (string, error) {
// Check function -> svc map
log.Printf("[%v] Checking for cached function service", m.Name)
result, err := api.functionService.Get(m)
if err == nil {
// Ok: return svc name
svc := result.(*funcSvc)
return svc.serviceName, nil
}
// None exists, so create a new funcSvc:
log.Printf("[%v] No cached function service found, creating one", m.Name)
// from Func -> get Env
log.Printf("[%v] getting environment for function", m.Name)
env, err := api.getFunctionEnv(m)
if err != nil {
return "", err
}
// from Env -> get GenericPool
log.Printf("[%v] getting generic pool for env", m.Name)
pool, err := api.poolMgr.GetPool(env)
if err != nil {
return "", err
}
// from GenericPool -> get one function container
log.Printf("[%v] getting function service from pool", m.Name)
funcSvc, err := pool.GetFuncSvc(m)
if err != nil {
return "", err
}
// add to cache
err = api.functionService.Set(m, funcSvc)
if err != nil {
// log and ignore error
log.Printf("Error saving function service: %v", err)
}
return funcSvc.serviceName, nil
}
func (api *API) Serve(port int) {
r := mux.NewRouter()
r.HandleFunc("/v1/getServiceForFunction", api.getServiceForFunctionApi).Methods("POST")
address := fmt.Sprintf(":%v", port)
log.Printf("starting poolmgr at port %v", port)
log.Fatal(http.ListenAndServe(address, handlers.LoggingHandler(os.Stdout, r)))
}