mirror of
https://github.com/fnproject/fn.git
synced 2022-10-28 21:29:17 +03:00
App ID (#641)
* App ID * Clean-up * Use ID or name to reference apps * Can use app by name or ID * Get rid of AppName for routes API and model routes API is completely backwards-compatible routes API accepts both app ID and name * Get rid of AppName from calls API and model * Fixing tests * Get rid of AppName from logs API and model * Restrict API to work with app names only * Addressing review comments * Fix for hybrid mode * Fix rebase problems * Addressing review comments * Addressing review comments pt.2 * Fixing test issue * Addressing review comments pt.3 * Updated docstring * Adjust UpdateApp SQL implementation to work with app IDs instead of names * Fixing tests * fmt after rebase * Make tests green again! * Use GetAppByID wherever it is necessary - adding new v2 endpoints to keep hybrid api/runner mode working - extract CallBase from Call object to expose that to a user (it doesn't include any app reference, as we do for all other API objects) * Get rid of GetAppByName * Adjusting server router setup * Make hybrid work again * Fix datastore tests * Fixing tests * Do not ignore app_id * Resolve issues after rebase * Updating test to make it work as it was * Tabula rasa for migrations * Adding calls API test - we need to ensure we give "App not found" for the missing app and missing call in first place - making previous test work (request missing call for the existing app) * Make datastore tests work fine with correctly applied migrations * Make CallFunction middleware work again had to adjust its implementation to set app ID before proceeding * The biggest rebase ever made * Fix 8's migration * Fix tests * Fix hybrid client * Fix tests problem * Increment app ID migration version * Fixing TestAppUpdate * Fix rebase issues * Addressing review comments * Renew vendor * Updated swagger doc per recommendations
This commit is contained in:
committed by
Reed Allman
parent
4e90844a67
commit
3c15ca6ea6
@@ -92,6 +92,12 @@ type Agent interface {
|
||||
// Enqueue is to use the agent's sweet sweet client bindings to remotely
|
||||
// queue async tasks and should be removed from Agent interface ASAP.
|
||||
Enqueue(context.Context, *models.Call) error
|
||||
|
||||
// GetAppID is to get the match of an app name to its ID
|
||||
GetAppID(ctx context.Context, appName string) (string, error)
|
||||
|
||||
// GetAppByID is to get the app by ID
|
||||
GetAppByID(ctx context.Context, appID string) (*models.App, error)
|
||||
}
|
||||
|
||||
type agent struct {
|
||||
@@ -151,6 +157,14 @@ func createAgent(da DataAccess, withDocker bool) Agent {
|
||||
return a
|
||||
}
|
||||
|
||||
func (a *agent) GetAppByID(ctx context.Context, appID string) (*models.App, error) {
|
||||
return a.da.GetAppByID(ctx, appID)
|
||||
}
|
||||
|
||||
func (a *agent) GetAppID(ctx context.Context, appName string) (string, error) {
|
||||
return a.da.GetAppID(ctx, appName)
|
||||
}
|
||||
|
||||
// TODO shuffle this around somewhere else (maybe)
|
||||
func (a *agent) Enqueue(ctx context.Context, call *models.Call) error {
|
||||
return a.da.Enqueue(ctx, call)
|
||||
@@ -645,7 +659,7 @@ func (a *agent) runHot(ctx context.Context, call *call, tok ResourceToken, state
|
||||
container, closer := NewHotContainer(call, &a.cfg)
|
||||
defer closer()
|
||||
|
||||
logger := logrus.WithFields(logrus.Fields{"id": container.id, "app": call.AppName, "route": call.Path, "image": call.Image, "memory": call.Memory, "cpus": call.CPUs, "format": call.Format, "idle_timeout": call.IdleTimeout})
|
||||
logger := logrus.WithFields(logrus.Fields{"id": container.id, "app_id": call.AppID, "route": call.Path, "image": call.Image, "memory": call.Memory, "cpus": call.CPUs, "format": call.Format, "idle_timeout": call.IdleTimeout})
|
||||
ctx = common.WithLogger(ctx, logger)
|
||||
|
||||
cookie, err := a.driver.Prepare(ctx, container)
|
||||
@@ -836,10 +850,10 @@ func NewHotContainer(call *call, cfg *AgentConfig) (*container, func()) {
|
||||
// have to be read or *BOTH* blocked consistently. In other words, we cannot block one and continue
|
||||
// reading from the other one without risking head-of-line blocking.
|
||||
stderr.Swap(newLineWriter(&logWriter{
|
||||
logrus.WithFields(logrus.Fields{"tag": "stderr", "app_name": call.AppName, "path": call.Path, "image": call.Image, "container_id": id}),
|
||||
logrus.WithFields(logrus.Fields{"tag": "stderr", "app_id": call.AppID, "path": call.Path, "image": call.Image, "container_id": id}),
|
||||
}))
|
||||
stdout.Swap(newLineWriter(&logWriter{
|
||||
logrus.WithFields(logrus.Fields{"tag": "stdout", "app_name": call.AppName, "path": call.Path, "image": call.Image, "container_id": id}),
|
||||
logrus.WithFields(logrus.Fields{"tag": "stdout", "app_id": call.AppID, "path": call.Path, "image": call.Image, "container_id": id}),
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/fnproject/fn/api/datastore"
|
||||
"github.com/fnproject/fn/api/id"
|
||||
"github.com/fnproject/fn/api/models"
|
||||
"github.com/fnproject/fn/api/mqs"
|
||||
"github.com/sirupsen/logrus"
|
||||
@@ -35,7 +36,7 @@ func init() {
|
||||
func checkExpectedHeaders(t *testing.T, expectedHeaders http.Header, receivedHeaders http.Header) {
|
||||
|
||||
checkMap := make([]string, 0, len(expectedHeaders))
|
||||
for k, _ := range expectedHeaders {
|
||||
for k := range expectedHeaders {
|
||||
checkMap = append(checkMap, k)
|
||||
}
|
||||
|
||||
@@ -46,7 +47,7 @@ func checkExpectedHeaders(t *testing.T, expectedHeaders http.Header, receivedHea
|
||||
}
|
||||
}
|
||||
|
||||
for i, _ := range checkMap {
|
||||
for i := range checkMap {
|
||||
if checkMap[i] == k {
|
||||
checkMap = append(checkMap[:i], checkMap[i+1:]...)
|
||||
break
|
||||
@@ -72,15 +73,15 @@ func TestCallConfigurationRequest(t *testing.T) {
|
||||
cfg := models.Config{"APP_VAR": "FOO"}
|
||||
rCfg := models.Config{"ROUTE_VAR": "BAR"}
|
||||
|
||||
app := &models.App{Name: appName, Config: cfg}
|
||||
app.SetDefaults()
|
||||
ds := datastore.NewMockInit(
|
||||
[]*models.App{
|
||||
{Name: appName, Config: cfg},
|
||||
},
|
||||
[]*models.App{app},
|
||||
[]*models.Route{
|
||||
{
|
||||
AppID: app.ID,
|
||||
Config: rCfg,
|
||||
Path: path,
|
||||
AppName: appName,
|
||||
Image: image,
|
||||
Type: typ,
|
||||
Format: format,
|
||||
@@ -112,7 +113,7 @@ func TestCallConfigurationRequest(t *testing.T) {
|
||||
|
||||
call, err := a.GetCall(
|
||||
WithWriter(w), // XXX (reed): order matters [for now]
|
||||
FromRequest(appName, path, req),
|
||||
FromRequest(app, path, req),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -124,8 +125,8 @@ func TestCallConfigurationRequest(t *testing.T) {
|
||||
if model.ID == "" {
|
||||
t.Fatal("model does not have id, GetCall should assign id")
|
||||
}
|
||||
if model.AppName != appName {
|
||||
t.Fatal("app name mismatch", model.AppName, appName)
|
||||
if model.AppID != app.ID {
|
||||
t.Fatal("app ID mismatch", model.ID, app.ID)
|
||||
}
|
||||
if model.Path != path {
|
||||
t.Fatal("path mismatch", model.Path, path)
|
||||
@@ -191,7 +192,8 @@ func TestCallConfigurationRequest(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCallConfigurationModel(t *testing.T) {
|
||||
appName := "myapp"
|
||||
app := &models.App{Name: "myapp"}
|
||||
app.SetDefaults()
|
||||
path := "/"
|
||||
image := "fnproject/fn-test-utils"
|
||||
const timeout = 1
|
||||
@@ -199,13 +201,13 @@ func TestCallConfigurationModel(t *testing.T) {
|
||||
const memory = 256
|
||||
CPUs := models.MilliCPUs(1000)
|
||||
method := "GET"
|
||||
url := "http://127.0.0.1:8080/r/" + appName + path
|
||||
url := "http://127.0.0.1:8080/r/" + app.Name + path
|
||||
payload := "payload"
|
||||
typ := "sync"
|
||||
format := "default"
|
||||
cfg := models.Config{
|
||||
"FN_FORMAT": format,
|
||||
"FN_APP_NAME": appName,
|
||||
"FN_APP_NAME": app.Name,
|
||||
"FN_PATH": path,
|
||||
"FN_MEMORY": strconv.Itoa(memory),
|
||||
"FN_CPUS": CPUs.String(),
|
||||
@@ -215,8 +217,8 @@ func TestCallConfigurationModel(t *testing.T) {
|
||||
}
|
||||
|
||||
cm := &models.Call{
|
||||
AppID: app.ID,
|
||||
Config: cfg,
|
||||
AppName: appName,
|
||||
Path: path,
|
||||
Image: image,
|
||||
Type: typ,
|
||||
@@ -252,7 +254,8 @@ func TestCallConfigurationModel(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAsyncCallHeaders(t *testing.T) {
|
||||
appName := "myapp"
|
||||
app := &models.App{Name: "myapp"}
|
||||
app.SetDefaults()
|
||||
path := "/"
|
||||
image := "fnproject/fn-test-utils"
|
||||
const timeout = 1
|
||||
@@ -260,7 +263,7 @@ func TestAsyncCallHeaders(t *testing.T) {
|
||||
const memory = 256
|
||||
CPUs := models.MilliCPUs(200)
|
||||
method := "GET"
|
||||
url := "http://127.0.0.1:8080/r/" + appName + path
|
||||
url := "http://127.0.0.1:8080/r/" + app.Name + path
|
||||
payload := "payload"
|
||||
typ := "async"
|
||||
format := "http"
|
||||
@@ -268,7 +271,7 @@ func TestAsyncCallHeaders(t *testing.T) {
|
||||
contentLength := strconv.FormatInt(int64(len(payload)), 10)
|
||||
config := map[string]string{
|
||||
"FN_FORMAT": format,
|
||||
"FN_APP_NAME": appName,
|
||||
"FN_APP_NAME": app.Name,
|
||||
"FN_PATH": path,
|
||||
"FN_MEMORY": strconv.Itoa(memory),
|
||||
"FN_CPUS": CPUs.String(),
|
||||
@@ -279,14 +282,14 @@ func TestAsyncCallHeaders(t *testing.T) {
|
||||
}
|
||||
headers := map[string][]string{
|
||||
// FromRequest would insert these from original HTTP request
|
||||
"Content-Type": []string{contentType},
|
||||
"Content-Length": []string{contentLength},
|
||||
"Content-Type": {contentType},
|
||||
"Content-Length": {contentLength},
|
||||
}
|
||||
|
||||
cm := &models.Call{
|
||||
AppID: app.ID,
|
||||
Config: config,
|
||||
Headers: headers,
|
||||
AppName: appName,
|
||||
Path: path,
|
||||
Image: image,
|
||||
Type: typ,
|
||||
@@ -389,7 +392,8 @@ func TestLoggerTooBig(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSubmitError(t *testing.T) {
|
||||
appName := "myapp"
|
||||
app := &models.App{Name: "myapp"}
|
||||
app.SetDefaults()
|
||||
path := "/"
|
||||
image := "fnproject/fn-test-utils"
|
||||
const timeout = 10
|
||||
@@ -397,13 +401,13 @@ func TestSubmitError(t *testing.T) {
|
||||
const memory = 256
|
||||
CPUs := models.MilliCPUs(200)
|
||||
method := "GET"
|
||||
url := "http://127.0.0.1:8080/r/" + appName + path
|
||||
url := "http://127.0.0.1:8080/r/" + app.Name + path
|
||||
payload := `{"sleepTime": 0, "isDebug": true, "isCrash": true}`
|
||||
typ := "sync"
|
||||
format := "default"
|
||||
config := map[string]string{
|
||||
"FN_FORMAT": format,
|
||||
"FN_APP_NAME": appName,
|
||||
"FN_APP_NAME": app.Name,
|
||||
"FN_PATH": path,
|
||||
"FN_MEMORY": strconv.Itoa(memory),
|
||||
"FN_CPUS": CPUs.String(),
|
||||
@@ -414,8 +418,8 @@ func TestSubmitError(t *testing.T) {
|
||||
}
|
||||
|
||||
cm := &models.Call{
|
||||
AppID: app.ID,
|
||||
Config: config,
|
||||
AppName: appName,
|
||||
Path: path,
|
||||
Image: image,
|
||||
Type: typ,
|
||||
@@ -469,15 +473,15 @@ func TestHTTPWithoutContentLengthWorks(t *testing.T) {
|
||||
path := "/hello"
|
||||
url := "http://127.0.0.1:8080/r/" + appName + path
|
||||
|
||||
app := &models.App{Name: appName}
|
||||
app.SetDefaults()
|
||||
// we need to load in app & route so that FromRequest works
|
||||
ds := datastore.NewMockInit(
|
||||
[]*models.App{
|
||||
{Name: appName},
|
||||
},
|
||||
[]*models.App{app},
|
||||
[]*models.Route{
|
||||
{
|
||||
Path: path,
|
||||
AppName: appName,
|
||||
AppID: app.ID,
|
||||
Image: "fnproject/fn-test-utils",
|
||||
Type: "sync",
|
||||
Format: "http", // this _is_ the test
|
||||
@@ -503,7 +507,7 @@ func TestHTTPWithoutContentLengthWorks(t *testing.T) {
|
||||
|
||||
// grab a buffer so we can read what gets written to this guy
|
||||
var out bytes.Buffer
|
||||
callI, err := a.GetCall(FromRequest(appName, path, req), WithWriter(&out))
|
||||
callI, err := a.GetCall(FromRequest(app, path, req), WithWriter(&out))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -538,7 +542,7 @@ func TestHTTPWithoutContentLengthWorks(t *testing.T) {
|
||||
|
||||
func TestGetCallReturnsResourceImpossibility(t *testing.T) {
|
||||
call := &models.Call{
|
||||
AppName: "yo",
|
||||
AppID: id.New().String(),
|
||||
Path: "/yoyo",
|
||||
Image: "fnproject/fn-test-utils",
|
||||
Type: "sync",
|
||||
@@ -565,6 +569,8 @@ func testCall() *models.Call {
|
||||
appName := "myapp"
|
||||
path := "/"
|
||||
image := "fnproject/fn-test-utils:latest"
|
||||
app := &models.App{Name: appName}
|
||||
app.SetDefaults()
|
||||
const timeout = 10
|
||||
const idleTimeout = 20
|
||||
const memory = 256
|
||||
@@ -594,9 +600,9 @@ func testCall() *models.Call {
|
||||
}
|
||||
|
||||
return &models.Call{
|
||||
AppID: app.ID,
|
||||
Config: config,
|
||||
Headers: headers,
|
||||
AppName: appName,
|
||||
Path: path,
|
||||
Image: image,
|
||||
Type: typ,
|
||||
@@ -637,16 +643,14 @@ func TestPipesAreClear(t *testing.T) {
|
||||
ca.Format = "http"
|
||||
ca.IdleTimeout = 60 // keep this bad boy alive
|
||||
ca.Timeout = 4 // short
|
||||
|
||||
app := &models.App{Name: "myapp", ID: ca.AppID}
|
||||
// we need to load in app & route so that FromRequest works
|
||||
ds := datastore.NewMockInit(
|
||||
[]*models.App{
|
||||
{Name: ca.AppName},
|
||||
},
|
||||
[]*models.App{app},
|
||||
[]*models.Route{
|
||||
{
|
||||
Path: ca.Path,
|
||||
AppName: ca.AppName,
|
||||
AppID: ca.AppID,
|
||||
Image: ca.Image,
|
||||
Type: ca.Type,
|
||||
Format: ca.Format,
|
||||
@@ -676,7 +680,7 @@ func TestPipesAreClear(t *testing.T) {
|
||||
req.Header.Set("Content-Length", fmt.Sprintf("%d", len(bodOne)))
|
||||
|
||||
var outOne bytes.Buffer
|
||||
callI, err := a.GetCall(FromRequest(ca.AppName, ca.Path, req), WithWriter(&outOne))
|
||||
callI, err := a.GetCall(FromRequest(app, ca.Path, req), WithWriter(&outOne))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -710,7 +714,7 @@ func TestPipesAreClear(t *testing.T) {
|
||||
req.Header.Set("Content-Length", fmt.Sprintf("%d", len(bodTwo)))
|
||||
|
||||
var outTwo bytes.Buffer
|
||||
callI, err = a.GetCall(FromRequest(ca.AppName, ca.Path, req), WithWriter(&outTwo))
|
||||
callI, err = a.GetCall(FromRequest(app, ca.Path, req), WithWriter(&outTwo))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -787,16 +791,16 @@ func TestPipesDontMakeSpuriousCalls(t *testing.T) {
|
||||
call.Format = "http"
|
||||
call.IdleTimeout = 60 // keep this bad boy alive
|
||||
call.Timeout = 4 // short
|
||||
|
||||
app := &models.App{Name: "myapp"}
|
||||
app.SetDefaults()
|
||||
app.ID = call.AppID
|
||||
// we need to load in app & route so that FromRequest works
|
||||
ds := datastore.NewMockInit(
|
||||
[]*models.App{
|
||||
{Name: call.AppName},
|
||||
},
|
||||
[]*models.App{app},
|
||||
[]*models.Route{
|
||||
{
|
||||
Path: call.Path,
|
||||
AppName: call.AppName,
|
||||
AppID: call.AppID,
|
||||
Image: call.Image,
|
||||
Type: call.Type,
|
||||
Format: call.Format,
|
||||
@@ -817,7 +821,7 @@ func TestPipesDontMakeSpuriousCalls(t *testing.T) {
|
||||
}
|
||||
|
||||
var outOne bytes.Buffer
|
||||
callI, err := a.GetCall(FromRequest(call.AppName, call.Path, req), WithWriter(&outOne))
|
||||
callI, err := a.GetCall(FromRequest(app, call.Path, req), WithWriter(&outOne))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -842,7 +846,7 @@ func TestPipesDontMakeSpuriousCalls(t *testing.T) {
|
||||
}
|
||||
|
||||
var outTwo bytes.Buffer
|
||||
callI, err = a.GetCall(FromRequest(call.AppName, call.Path, req), WithWriter(&outTwo))
|
||||
callI, err = a.GetCall(FromRequest(app, call.Path, req), WithWriter(&outTwo))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ func (a *agent) asyncRun(ctx context.Context, model *models.Call) {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
ctx, err = tag.New(ctx,
|
||||
tag.Insert(appKey, model.AppName),
|
||||
tag.Insert(appKey, model.AppID),
|
||||
tag.Insert(pathKey, model.Path),
|
||||
)
|
||||
if err != nil {
|
||||
|
||||
@@ -49,14 +49,9 @@ type Param struct {
|
||||
}
|
||||
type Params []Param
|
||||
|
||||
func FromRequest(appName, path string, req *http.Request) CallOpt {
|
||||
func FromRequest(app *models.App, path string, req *http.Request) CallOpt {
|
||||
return func(a *agent, c *call) error {
|
||||
app, err := a.da.GetApp(req.Context(), appName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
route, err := a.da.GetRoute(req.Context(), appName, path)
|
||||
route, err := a.da.GetRoute(req.Context(), app.ID, path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -87,10 +82,9 @@ func FromRequest(appName, path string, req *http.Request) CallOpt {
|
||||
}
|
||||
|
||||
c.Call = &models.Call{
|
||||
ID: id,
|
||||
AppName: appName,
|
||||
Path: route.Path,
|
||||
Image: route.Image,
|
||||
ID: id,
|
||||
Path: route.Path,
|
||||
Image: route.Image,
|
||||
// Delay: 0,
|
||||
Type: route.Type,
|
||||
Format: route.Format,
|
||||
@@ -106,6 +100,7 @@ func FromRequest(appName, path string, req *http.Request) CallOpt {
|
||||
CreatedAt: strfmt.DateTime(time.Now()),
|
||||
URL: reqURL(req),
|
||||
Method: req.Method,
|
||||
AppID: app.ID,
|
||||
}
|
||||
|
||||
c.req = req
|
||||
@@ -247,11 +242,11 @@ func (a *agent) GetCall(opts ...CallOpt) (Call, error) {
|
||||
c.ct = a
|
||||
|
||||
ctx, _ := common.LoggerWithFields(c.req.Context(),
|
||||
logrus.Fields{"id": c.ID, "app": c.AppName, "route": c.Path})
|
||||
logrus.Fields{"id": c.ID, "app_id": c.AppID, "route": c.Path})
|
||||
c.req = c.req.WithContext(ctx)
|
||||
|
||||
// setup stderr logger separate (don't inherit ctx vars)
|
||||
logger := logrus.WithFields(logrus.Fields{"user_log": true, "app_name": c.AppName, "path": c.Path, "image": c.Image, "call_id": c.ID})
|
||||
logger := logrus.WithFields(logrus.Fields{"user_log": true, "app_id": c.AppID, "path": c.Path, "image": c.Image, "call_id": c.ID})
|
||||
c.stderr = setupLogger(logger, a.cfg.MaxLogSize)
|
||||
if c.w == nil {
|
||||
// send STDOUT to logs if no writer given (async...)
|
||||
|
||||
@@ -16,11 +16,13 @@ import (
|
||||
// but actually operate on the data in different ways (by direct access or by
|
||||
// mediation through an API node).
|
||||
type DataAccess interface {
|
||||
// GetApp abstracts querying the datastore for an app.
|
||||
GetApp(ctx context.Context, appName string) (*models.App, error)
|
||||
GetAppID(ctx context.Context, appName string) (string, error)
|
||||
|
||||
// GetAppByID abstracts querying the datastore for an app.
|
||||
GetAppByID(ctx context.Context, appID string) (*models.App, error)
|
||||
|
||||
// GetRoute abstracts querying the datastore for a route within an app.
|
||||
GetRoute(ctx context.Context, appName string, routePath string) (*models.Route, error)
|
||||
GetRoute(ctx context.Context, appID string, routePath string) (*models.Route, error)
|
||||
|
||||
// Enqueue will add a Call to the queue (ultimately forwards to mq.Push).
|
||||
Enqueue(ctx context.Context, mCall *models.Call) error
|
||||
@@ -54,16 +56,20 @@ func NewCachedDataAccess(da DataAccess) DataAccess {
|
||||
return cda
|
||||
}
|
||||
|
||||
func routeCacheKey(appname, path string) string {
|
||||
return "r:" + appname + "\x00" + path
|
||||
func routeCacheKey(app, path string) string {
|
||||
return "r:" + app + "\x00" + path
|
||||
}
|
||||
|
||||
func appCacheKey(appname string) string {
|
||||
return "a:" + appname
|
||||
func appIDCacheKey(appID string) string {
|
||||
return "a:" + appID
|
||||
}
|
||||
|
||||
func (da *CachedDataAccess) GetApp(ctx context.Context, appName string) (*models.App, error) {
|
||||
key := appCacheKey(appName)
|
||||
func (da *CachedDataAccess) GetAppID(ctx context.Context, appName string) (string, error) {
|
||||
return da.DataAccess.GetAppID(ctx, appName)
|
||||
}
|
||||
|
||||
func (da *CachedDataAccess) GetAppByID(ctx context.Context, appID string) (*models.App, error) {
|
||||
key := appIDCacheKey(appID)
|
||||
app, ok := da.cache.Get(key)
|
||||
if ok {
|
||||
return app.(*models.App), nil
|
||||
@@ -71,7 +77,7 @@ func (da *CachedDataAccess) GetApp(ctx context.Context, appName string) (*models
|
||||
|
||||
resp, err := da.singleflight.Do(key,
|
||||
func() (interface{}, error) {
|
||||
return da.DataAccess.GetApp(ctx, appName)
|
||||
return da.DataAccess.GetAppByID(ctx, appID)
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
@@ -82,8 +88,8 @@ func (da *CachedDataAccess) GetApp(ctx context.Context, appName string) (*models
|
||||
return app.(*models.App), nil
|
||||
}
|
||||
|
||||
func (da *CachedDataAccess) GetRoute(ctx context.Context, appName string, routePath string) (*models.Route, error) {
|
||||
key := routeCacheKey(appName, routePath)
|
||||
func (da *CachedDataAccess) GetRoute(ctx context.Context, appID string, routePath string) (*models.Route, error) {
|
||||
key := routeCacheKey(appID, routePath)
|
||||
r, ok := da.cache.Get(key)
|
||||
if ok {
|
||||
return r.(*models.Route), nil
|
||||
@@ -91,7 +97,7 @@ func (da *CachedDataAccess) GetRoute(ctx context.Context, appName string, routeP
|
||||
|
||||
resp, err := da.singleflight.Do(key,
|
||||
func() (interface{}, error) {
|
||||
return da.DataAccess.GetRoute(ctx, appName, routePath)
|
||||
return da.DataAccess.GetRoute(ctx, appID, routePath)
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
@@ -117,12 +123,16 @@ func NewDirectDataAccess(ds models.Datastore, ls models.LogStore, mq models.Mess
|
||||
return da
|
||||
}
|
||||
|
||||
func (da *directDataAccess) GetApp(ctx context.Context, appName string) (*models.App, error) {
|
||||
return da.ds.GetApp(ctx, appName)
|
||||
func (da *directDataAccess) GetAppID(ctx context.Context, appName string) (string, error) {
|
||||
return da.ds.GetAppID(ctx, appName)
|
||||
}
|
||||
|
||||
func (da *directDataAccess) GetRoute(ctx context.Context, appName string, routePath string) (*models.Route, error) {
|
||||
return da.ds.GetRoute(ctx, appName, routePath)
|
||||
func (da *directDataAccess) GetAppByID(ctx context.Context, appID string) (*models.App, error) {
|
||||
return da.ds.GetAppByID(ctx, appID)
|
||||
}
|
||||
|
||||
func (da *directDataAccess) GetRoute(ctx context.Context, appID string, routePath string) (*models.Route, error) {
|
||||
return da.ds.GetRoute(ctx, appID, routePath)
|
||||
}
|
||||
|
||||
func (da *directDataAccess) Enqueue(ctx context.Context, mCall *models.Call) error {
|
||||
@@ -155,7 +165,7 @@ func (da *directDataAccess) Finish(ctx context.Context, mCall *models.Call, stde
|
||||
// note: Not returning err here since the job could have already finished successfully.
|
||||
}
|
||||
|
||||
if err := da.ls.InsertLog(ctx, mCall.AppName, mCall.ID, stderr); err != nil {
|
||||
if err := da.ls.InsertLog(ctx, mCall.AppID, mCall.ID, stderr); err != nil {
|
||||
common.Logger(ctx).WithError(err).Error("error uploading log")
|
||||
// note: Not returning err here since the job could have already finished successfully.
|
||||
}
|
||||
|
||||
@@ -118,18 +118,29 @@ func (cl *client) Finish(ctx context.Context, c *models.Call, r io.Reader, async
|
||||
return err
|
||||
}
|
||||
|
||||
func (cl *client) GetApp(ctx context.Context, appName string) (*models.App, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "hybrid_client_get_app")
|
||||
func (cl *client) GetAppID(ctx context.Context, appName string) (string, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "hybrid_client_get_app_id")
|
||||
defer span.End()
|
||||
|
||||
var a struct {
|
||||
A models.App `json:"app"`
|
||||
}
|
||||
err := cl.do(ctx, nil, &a, "GET", "apps", appName)
|
||||
return a.A.ID, err
|
||||
}
|
||||
|
||||
func (cl *client) GetAppByID(ctx context.Context, appID string) (*models.App, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "hybrid_client_get_app_id")
|
||||
defer span.End()
|
||||
|
||||
var a struct {
|
||||
A models.App `json:"app"`
|
||||
}
|
||||
err := cl.do(ctx, nil, &a, "GET", "runner", "apps", appID)
|
||||
return &a.A, err
|
||||
}
|
||||
|
||||
func (cl *client) GetRoute(ctx context.Context, appName, route string) (*models.Route, error) {
|
||||
func (cl *client) GetRoute(ctx context.Context, appID, route string) (*models.Route, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "hybrid_client_get_route")
|
||||
defer span.End()
|
||||
|
||||
@@ -137,7 +148,7 @@ func (cl *client) GetRoute(ctx context.Context, appName, route string) (*models.
|
||||
var r struct {
|
||||
R models.Route `json:"route"`
|
||||
}
|
||||
err := cl.do(ctx, nil, &r, "GET", "apps", appName, "routes", strings.TrimPrefix(route, "/"))
|
||||
err := cl.do(ctx, nil, &r, "GET", "runner", "apps", appID, "routes", strings.TrimPrefix(route, "/"))
|
||||
return &r.R, err
|
||||
}
|
||||
|
||||
@@ -162,7 +173,7 @@ func (cl *client) do(ctx context.Context, request, result interface{}, method st
|
||||
err = cl.once(ctx, request, result, method, url...)
|
||||
switch err := err.(type) {
|
||||
case nil:
|
||||
return err
|
||||
return nil
|
||||
case *httpErr:
|
||||
if err.code < 500 {
|
||||
return err
|
||||
|
||||
@@ -17,6 +17,18 @@ func NewNopDataStore() (agent.DataAccess, error) {
|
||||
return &nopDataStore{}, nil
|
||||
}
|
||||
|
||||
func (cl *nopDataStore) GetAppID(ctx context.Context, appName string) (string, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "nop_datastore_get_app_id")
|
||||
defer span.End()
|
||||
return "", errors.New("should not call GetAppID on a NOP data store")
|
||||
}
|
||||
|
||||
func (cl *nopDataStore) GetAppByID(ctx context.Context, appID string) (*models.App, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "nop_datastore_get_app_by_id")
|
||||
defer span.End()
|
||||
return nil, errors.New("should not call GetAppByID on a NOP data store")
|
||||
}
|
||||
|
||||
func (cl *nopDataStore) Enqueue(ctx context.Context, c *models.Call) error {
|
||||
ctx, span := trace.StartSpan(ctx, "nop_datastore_enqueue")
|
||||
defer span.End()
|
||||
@@ -41,12 +53,6 @@ func (cl *nopDataStore) Finish(ctx context.Context, c *models.Call, r io.Reader,
|
||||
return nil // It's ok to call this method, and it does no operations
|
||||
}
|
||||
|
||||
func (cl *nopDataStore) GetApp(ctx context.Context, appName string) (*models.App, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "nop_datastore_get_app")
|
||||
defer span.End()
|
||||
return nil, errors.New("Should not call GetApp on a NOP data store")
|
||||
}
|
||||
|
||||
func (cl *nopDataStore) GetRoute(ctx context.Context, appName, route string) (*models.Route, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "nop_datastore_get_route")
|
||||
defer span.End()
|
||||
|
||||
@@ -112,6 +112,16 @@ func NewLBAgent(da DataAccess, rp pool.RunnerPool, p pool.Placer) (Agent, error)
|
||||
return a, nil
|
||||
}
|
||||
|
||||
// GetAppID is to get the match of an app name to its ID
|
||||
func (a *lbAgent) GetAppID(ctx context.Context, appName string) (string, error) {
|
||||
return a.delegatedAgent.GetAppID(ctx, appName)
|
||||
}
|
||||
|
||||
// GetAppByID is to get the app by ID
|
||||
func (a *lbAgent) GetAppByID(ctx context.Context, appID string) (*models.App, error) {
|
||||
return a.delegatedAgent.GetAppByID(ctx, appID)
|
||||
}
|
||||
|
||||
// GetCall delegates to the wrapped agent but disables the capacity check as
|
||||
// this agent isn't actually running the call.
|
||||
func (a *lbAgent) GetCall(opts ...CallOpt) (Call, error) {
|
||||
|
||||
@@ -250,6 +250,14 @@ type pureRunner struct {
|
||||
capacity CapacityGate
|
||||
}
|
||||
|
||||
func (pr *pureRunner) GetAppID(ctx context.Context, appName string) (string, error) {
|
||||
return pr.a.GetAppID(ctx, appName)
|
||||
}
|
||||
|
||||
func (pr *pureRunner) GetAppByID(ctx context.Context, appID string) (*models.App, error) {
|
||||
return pr.a.GetAppByID(ctx, appID)
|
||||
}
|
||||
|
||||
func (pr *pureRunner) GetCall(opts ...CallOpt) (Call, error) {
|
||||
return pr.a.GetCall(opts...)
|
||||
}
|
||||
|
||||
@@ -284,7 +284,7 @@ func getSlotQueueKey(call *call) string {
|
||||
hash.Reset()
|
||||
defer shapool.Put(hash)
|
||||
|
||||
hash.Write(unsafeBytes(call.AppName))
|
||||
hash.Write(unsafeBytes(call.AppID))
|
||||
hash.Write(unsafeBytes("\x00"))
|
||||
hash.Write(unsafeBytes(call.Path))
|
||||
hash.Write(unsafeBytes("\x00"))
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/fnproject/fn/api/id"
|
||||
"github.com/fnproject/fn/api/models"
|
||||
)
|
||||
|
||||
@@ -266,6 +267,7 @@ func TestSlotQueueBasic3(t *testing.T) {
|
||||
|
||||
func BenchmarkSlotKey(b *testing.B) {
|
||||
appName := "myapp"
|
||||
appID := id.New().String()
|
||||
path := "/"
|
||||
image := "fnproject/fn-test-utils"
|
||||
const timeout = 1
|
||||
@@ -290,7 +292,7 @@ func BenchmarkSlotKey(b *testing.B) {
|
||||
|
||||
cm := &models.Call{
|
||||
Config: cfg,
|
||||
AppName: appName,
|
||||
AppID: appID,
|
||||
Path: path,
|
||||
Image: image,
|
||||
Type: typ,
|
||||
|
||||
Reference in New Issue
Block a user