* 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:
Denis Makogon
2018-03-26 21:19:36 +03:00
committed by Reed Allman
parent 4e90844a67
commit 3c15ca6ea6
59 changed files with 1101 additions and 657 deletions

View File

@@ -4,10 +4,12 @@ import (
"time"
"unicode"
"github.com/fnproject/fn/api/id"
"github.com/go-openapi/strfmt"
)
type App struct {
ID string `json:"id" db:"id"`
Name string `json:"name" db:"name"`
Config Config `json:"config,omitempty" db:"config"`
Annotations Annotations `json:"annotations,omitempty" db:"annotations"`
@@ -26,6 +28,9 @@ func (a *App) SetDefaults() {
// keeps the json from being nil
a.Config = map[string]string{}
}
if a.ID == "" {
a.ID = id.New().String()
}
}
func (a *App) Validate() error {
@@ -58,7 +63,7 @@ func (a *App) Clone() *App {
clone.Config[k] = v
}
}
clone.ID = a.ID
return clone
}
@@ -67,6 +72,7 @@ func (a1 *App) Equals(a2 *App) bool {
// the RHS of && won't eval if eq==false so config checking is lazy
eq := true
eq = eq && a1.ID == a2.ID
eq = eq && a1.Name == a2.Name
eq = eq && a1.Config.Equals(a2.Config)
eq = eq && a1.Annotations.Equals(a2.Annotations)

View File

@@ -27,12 +27,6 @@ const (
var possibleStatuses = [...]string{"delayed", "queued", "running", "success", "error", "cancelled"}
type CallLog struct {
CallID string `json:"call_id" db:"id"`
Log string `json:"log" db:"log"`
AppName string `json:"app_name" db:"app_name"`
}
// Call is a representation of a specific invocation of a route.
type Call struct {
// Unique identifier representing a specific call.
@@ -75,9 +69,6 @@ type Call struct {
// - client_request - Request was cancelled by a client.
Status string `json:"status" db:"status"`
// App this call belongs to.
AppName string `json:"app_name" db:"app_name"`
// Path of the route that is responsible for this call
Path string `json:"path" db:"path"`
@@ -147,11 +138,13 @@ type Call struct {
// Error is the reason why the call failed, it is only non-empty if
// status is equal to "error".
Error string `json:"error,omitempty" db:"error"`
// App this call belongs to.
AppID string `json:"app_id" db:"app_id"`
}
type CallFilter struct {
Path string // match
AppName string // match
AppID string // match
FromTime strfmt.DateTime
ToTime strfmt.DateTime
Cursor string

View File

@@ -7,10 +7,15 @@ import (
)
type Datastore interface {
// GetApp gets an App by name.
// GetAppByID gets an App by ID.
// Returns ErrDatastoreEmptyAppID for empty appID.
// Returns ErrAppsNotFound if no app is found.
GetAppByID(ctx context.Context, appID string) (*App, error)
// GetAppID gets an app ID by app name, ensures if app exists.
// Returns ErrDatastoreEmptyAppName for empty appName.
// Returns ErrAppsNotFound if no app is found.
GetApp(ctx context.Context, appName string) (*App, error)
GetAppID(ctx context.Context, appName string) (string, error)
// GetApps gets a slice of Apps, optionally filtered by name.
// Missing filter or empty name will match all Apps.
@@ -28,17 +33,17 @@ type Datastore interface {
// RemoveApp removes the App named appName. Returns ErrDatastoreEmptyAppName if appName is empty.
// Returns ErrAppsNotFound if an App is not found.
RemoveApp(ctx context.Context, appName string) error
RemoveApp(ctx context.Context, appID string) error
// GetRoute looks up a matching Route for appName and the literal request route routePath.
// Returns ErrDatastoreEmptyAppName when appName is empty, and ErrDatastoreEmptyRoutePath when
// routePath is empty.
// Returns ErrRoutesNotFound when no matching route is found.
GetRoute(ctx context.Context, appName, routePath string) (*Route, error)
GetRoute(ctx context.Context, appID, routePath string) (*Route, error)
// GetRoutesByApp gets a slice of routes for a appName, optionally filtering on filter (filter.AppName is ignored).
// Returns ErrDatastoreEmptyAppName if appName is empty.
GetRoutesByApp(ctx context.Context, appName string, filter *RouteFilter) ([]*Route, error)
GetRoutesByApp(ctx context.Context, appID string, filter *RouteFilter) ([]*Route, error)
// InsertRoute inserts a route. Returns ErrDatastoreEmptyRoute when route is nil, and ErrDatastoreEmptyAppName
// or ErrDatastoreEmptyRoutePath for empty AppName or Path.
@@ -49,9 +54,9 @@ type Datastore interface {
// ErrDatastoreEmptyAppName or ErrDatastoreEmptyRoutePath for empty AppName or Path.
UpdateRoute(ctx context.Context, route *Route) (*Route, error)
// RemoveRoute removes a route. Returns ErrDatastoreEmptyAppName when appName is empty, and
// RemoveRoute removes a route. Returns ErrDatastoreEmptyAppID when appName is empty, and
// ErrDatastoreEmptyRoutePath when routePath is empty. Returns ErrRoutesNotFound when no route exists.
RemoveRoute(ctx context.Context, appName, routePath string) error
RemoveRoute(ctx context.Context, appID, routePath string) error
// InsertCall inserts a call into the datastore, it will error if the call already
// exists.
@@ -63,7 +68,7 @@ type Datastore interface {
UpdateCall(ctx context.Context, from *Call, to *Call) error
// GetCall returns a call at a certain id and app name.
GetCall(ctx context.Context, appName, callID string) (*Call, error)
GetCall(ctx context.Context, appID, callID string) (*Call, error)
// GetCalls returns a list of calls that satisfy the given CallFilter. If no
// calls exist, an empty list and a nil error are returned.

View File

@@ -60,6 +60,10 @@ var (
code: http.StatusBadRequest,
error: errors.New("Missing app"),
}
ErrDatastoreEmptyAppID = err{
code: http.StatusBadRequest,
error: errors.New("Missing app ID"),
}
ErrDatastoreEmptyRoute = err{
code: http.StatusBadRequest,
error: errors.New("Missing route"),
@@ -112,7 +116,7 @@ var (
code: http.StatusBadRequest,
error: errors.New("Invalid route Format"),
}
ErrRoutesMissingAppName = err{
ErrRoutesMissingAppID = err{
code: http.StatusBadRequest,
error: errors.New("Missing route AppName"),
}

View File

@@ -8,11 +8,11 @@ import (
type LogStore interface {
// InsertLog will insert the log at callID, overwriting if it previously
// existed.
InsertLog(ctx context.Context, appName, callID string, callLog io.Reader) error
InsertLog(ctx context.Context, appID, callID string, callLog io.Reader) error
// GetLog will return the log at callID, an error will be returned if the log
// cannot be found.
GetLog(ctx context.Context, appName, callID string) (io.Reader, error)
GetLog(ctx context.Context, appID, callID string) (io.Reader, error)
// TODO we should probably allow deletion of a range of logs (also calls)?
// common cases for deletion will be:

View File

@@ -25,7 +25,7 @@ var RouteMaxMemory = uint64(8 * 1024)
type Routes []*Route
type Route struct {
AppName string `json:"app_name" db:"app_name"`
AppID string `json:"app_id" db:"app_id"`
Path string `json:"path" db:"path"`
Image string `json:"image" db:"image"`
Memory uint64 `json:"memory" db:"memory"`
@@ -83,8 +83,8 @@ func (r *Route) SetDefaults() {
// Validate validates all field values, returning the first error, if any.
func (r *Route) Validate() error {
if r.AppName == "" {
return ErrRoutesMissingAppName
if r.AppID == "" {
return ErrRoutesMissingAppID
}
if r.Path == "" {
@@ -164,7 +164,7 @@ func (r1 *Route) Equals(r2 *Route) bool {
// the RHS of && won't eval if eq==false so config/headers checking is lazy
eq := true
eq = eq && r1.AppName == r2.AppName
eq = eq && r1.AppID == r2.AppID
eq = eq && r1.Path == r2.Path
eq = eq && r1.Image == r2.Image
eq = eq && r1.Memory == r2.Memory
@@ -244,7 +244,7 @@ func (r *Route) Update(patch *Route) {
type RouteFilter struct {
PathPrefix string // this is prefix match TODO
AppName string // this is exact match (important for security)
AppID string // this is exact match (important for security)
Image string // this is exact match
Cursor string

View File

@@ -1,13 +1,14 @@
package models
import (
"github.com/fnproject/fn/api/id"
"testing"
)
func TestRouteSimple(t *testing.T) {
route1 := &Route{
AppName: "test",
AppID: id.New().String(),
Path: "/some",
Image: "foo",
Memory: 128,
@@ -24,7 +25,7 @@ func TestRouteSimple(t *testing.T) {
}
route2 := &Route{
AppName: "test",
AppID: id.New().String(),
Path: "/some",
Image: "foo",
Memory: 128,