added config to apps and routes

This commit is contained in:
Pedro Nasser
2016-08-26 23:04:57 -03:00
parent 609d767c3f
commit 2782a6db54
13 changed files with 108 additions and 65 deletions

View File

@@ -208,13 +208,13 @@ func (ds *BoltDatastore) StoreRoute(route *models.Route) (*models.Route, error)
return route, nil return route, nil
} }
func (ds *BoltDatastore) RemoveRoute(appName, routeName string) error { func (ds *BoltDatastore) RemoveRoute(appName, routePath string) error {
if appName == "" { if appName == "" {
return models.ErrDatastoreEmptyAppName return models.ErrDatastoreEmptyAppName
} }
if routeName == "" { if routePath == "" {
return models.ErrDatastoreEmptyRouteName return models.ErrDatastoreEmptyRoutePath
} }
err := ds.db.Update(func(tx *bolt.Tx) error { err := ds.db.Update(func(tx *bolt.Tx) error {
@@ -223,7 +223,7 @@ func (ds *BoltDatastore) RemoveRoute(appName, routeName string) error {
return err return err
} }
err = b.Delete([]byte(routeName)) err = b.Delete([]byte(routePath))
if err != nil { if err != nil {
return err return err
} }
@@ -235,13 +235,13 @@ func (ds *BoltDatastore) RemoveRoute(appName, routeName string) error {
return nil return nil
} }
func (ds *BoltDatastore) GetRoute(appName, routeName string) (*models.Route, error) { func (ds *BoltDatastore) GetRoute(appName, routePath string) (*models.Route, error) {
if appName == "" { if appName == "" {
return nil, models.ErrDatastoreEmptyAppName return nil, models.ErrDatastoreEmptyAppName
} }
if routeName == "" { if routePath == "" {
return nil, models.ErrDatastoreEmptyRouteName return nil, models.ErrDatastoreEmptyRoutePath
} }
var route *models.Route var route *models.Route
@@ -251,7 +251,7 @@ func (ds *BoltDatastore) GetRoute(appName, routeName string) (*models.Route, err
return err return err
} }
v := b.Get([]byte(routeName)) v := b.Get([]byte(routePath))
if v != nil { if v != nil {
err = json.Unmarshal(v, &route) err = json.Unmarshal(v, &route)
} }

View File

@@ -118,7 +118,7 @@ func TestBolt(t *testing.T) {
t.Fatalf("Test GetRoute: error: %s", err) t.Fatalf("Test GetRoute: error: %s", err)
} }
if route.Path != testRoute.Path { if route.Path != testRoute.Path {
t.Fatalf("Test GetRoute: expected `route.Name` to be `%s` but it was `%s`", route.Path, testRoute.Path) t.Fatalf("Test GetRoute: expected `route.Path` to be `%s` but it was `%s`", route.Path, testRoute.Path)
} }
// Testing list routes // Testing list routes

View File

@@ -9,46 +9,73 @@ type Mock struct {
FakeRoutes []*models.Route FakeRoutes []*models.Route
} }
func (m *Mock) GetApp(app string) (*models.App, error) { func (m *Mock) GetApp(appName string) (*models.App, error) {
return m.FakeApp, nil app := m.FakeApp
if app == nil && m.FakeApps != nil {
for _, a := range m.FakeApps {
if a.Name == appName {
app = a
}
}
}
return app, nil
} }
func (m *Mock) GetApps(appFilter *models.AppFilter) ([]*models.App, error) { func (m *Mock) GetApps(appFilter *models.AppFilter) ([]*models.App, error) {
// TODO: improve this mock method
return m.FakeApps, nil return m.FakeApps, nil
} }
func (m *Mock) StoreApp(app *models.App) (*models.App, error) { func (m *Mock) StoreApp(app *models.App) (*models.App, error) {
// TODO: improve this mock method
return m.FakeApp, nil return m.FakeApp, nil
} }
func (m *Mock) RemoveApp(app string) error { func (m *Mock) RemoveApp(appName string) error {
// TODO: improve this mock method
return nil return nil
} }
func (m *Mock) GetRoute(app, route string) (*models.Route, error) { func (m *Mock) GetRoute(appName, routePath string) (*models.Route, error) {
return m.FakeRoute, nil route := m.FakeRoute
if route == nil && m.FakeRoutes != nil {
for _, r := range m.FakeRoutes {
if r.AppName == appName && r.Path == routePath {
route = r
}
}
}
return route, nil
} }
func (m *Mock) GetRoutes(routeFilter *models.RouteFilter) ([]*models.Route, error) { func (m *Mock) GetRoutes(routeFilter *models.RouteFilter) ([]*models.Route, error) {
// TODO: improve this mock method
return m.FakeRoutes, nil return m.FakeRoutes, nil
} }
func (m *Mock) GetRoutesByApp(appName string, routeFilter *models.RouteFilter) ([]*models.Route, error) { func (m *Mock) GetRoutesByApp(appName string, routeFilter *models.RouteFilter) ([]*models.Route, error) {
// TODO: improve this mock method
return m.FakeRoutes, nil return m.FakeRoutes, nil
} }
func (m *Mock) StoreRoute(route *models.Route) (*models.Route, error) { func (m *Mock) StoreRoute(route *models.Route) (*models.Route, error) {
// TODO: improve this mock method
return m.FakeRoute, nil return m.FakeRoute, nil
} }
func (m *Mock) RemoveRoute(app, route string) error { func (m *Mock) RemoveRoute(appName, routePath string) error {
// TODO: improve this mock method
return nil return nil
} }
func (m *Mock) Put(key, value []byte) error { func (m *Mock) Put(key, value []byte) error {
// TODO: improve this mock method
return nil return nil
} }
func (m *Mock) Get(key []byte) ([]byte, error) { func (m *Mock) Get(key []byte) ([]byte, error) {
// TODO: improve this mock method
return []byte{}, nil return []byte{}, nil
} }

View File

@@ -17,11 +17,13 @@ CREATE TABLE IF NOT EXISTS routes (
path text NOT NULL, path text NOT NULL,
image character varying(256) NOT NULL, image character varying(256) NOT NULL,
headers text NOT NULL, headers text NOT NULL,
config text NOT NULL,
PRIMARY KEY (app_name, path) PRIMARY KEY (app_name, path)
);` );`
const appsTableCreate = `CREATE TABLE IF NOT EXISTS apps ( const appsTableCreate = `CREATE TABLE IF NOT EXISTS apps (
name character varying(256) NOT NULL PRIMARY KEY name character varying(256) NOT NULL PRIMARY KEY
config text NOT NULL,
);` );`
const extrasTableCreate = `CREATE TABLE IF NOT EXISTS extras ( const extrasTableCreate = `CREATE TABLE IF NOT EXISTS extras (
@@ -73,13 +75,20 @@ func New(url *url.URL) (models.Datastore, error) {
} }
func (ds *PostgresDatastore) StoreApp(app *models.App) (*models.App, error) { func (ds *PostgresDatastore) StoreApp(app *models.App) (*models.App, error) {
_, err := ds.db.Exec(` cbyte, err := json.Marshal(app.Config)
INSERT INTO apps (name) if err != nil {
VALUES ($1) return nil, err
ON CONFLICT (name) DO NOTHING }
RETURNING name;
`, app.Name) _, err = ds.db.Exec(`
// todo: after we support headers, the conflict should update the headers. INSERT INTO apps (name, config)
VALUES ($1, $2)
ON CONFLICT (app_name) DO UPDATE SET
config = $2;
`,
app.Name,
string(cbyte),
)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -105,12 +114,15 @@ func (ds *PostgresDatastore) GetApp(name string) (*models.App, error) {
row := ds.db.QueryRow("SELECT name FROM apps WHERE name=$1", name) row := ds.db.QueryRow("SELECT name FROM apps WHERE name=$1", name)
var resName string var resName string
err := row.Scan(&resName) var config string
err := row.Scan(&resName, &config)
res := &models.App{ res := &models.App{
Name: resName, Name: resName,
} }
json.Unmarshal([]byte(config), &res.Config)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -155,32 +167,36 @@ func (ds *PostgresDatastore) GetApps(filter *models.AppFilter) ([]*models.App, e
} }
func (ds *PostgresDatastore) StoreRoute(route *models.Route) (*models.Route, error) { func (ds *PostgresDatastore) StoreRoute(route *models.Route) (*models.Route, error) {
var headers string
hbyte, err := json.Marshal(route.Headers) hbyte, err := json.Marshal(route.Headers)
if err != nil { if err != nil {
return nil, err return nil, err
} }
headers = string(hbyte) cbyte, err := json.Marshal(route.Config)
if err != nil {
return nil, err
}
_, err = ds.db.Exec(` _, err = ds.db.Exec(`
INSERT INTO routes ( INSERT INTO routes (
app_name, app_name,
path, path,
image, image,
headers headers,
config
) )
VALUES ($1, $2, $3, $4) VALUES ($1, $2, $3, $4)
ON CONFLICT (app_name, path) DO UPDATE SET ON CONFLICT (app_name, path) DO UPDATE SET
path = $2, path = $2,
image = $3, image = $3,
headers = $4; headers = $4;
config = $5;
`, `,
route.AppName, route.AppName,
route.Path, route.Path,
route.Image, route.Image,
headers, string(hbyte),
string(cbyte),
) )
if err != nil { if err != nil {
@@ -189,11 +205,11 @@ func (ds *PostgresDatastore) StoreRoute(route *models.Route) (*models.Route, err
return route, nil return route, nil
} }
func (ds *PostgresDatastore) RemoveRoute(appName, routeName string) error { func (ds *PostgresDatastore) RemoveRoute(appName, routePath string) error {
_, err := ds.db.Exec(` _, err := ds.db.Exec(`
DELETE FROM routes DELETE FROM routes
WHERE name = $1 WHERE path = $1
`, routeName) `, routePath)
if err != nil { if err != nil {
return err return err
@@ -203,27 +219,30 @@ func (ds *PostgresDatastore) RemoveRoute(appName, routeName string) error {
func scanRoute(scanner rowScanner, route *models.Route) error { func scanRoute(scanner rowScanner, route *models.Route) error {
var headerStr string var headerStr string
var configStr string
err := scanner.Scan( err := scanner.Scan(
// &route.Name,
&route.AppName, &route.AppName,
&route.Path, &route.Path,
&route.Image, &route.Image,
&headerStr, &headerStr,
&configStr,
) )
if headerStr == "" { if headerStr == "" {
return models.ErrRoutesNotFound return models.ErrRoutesNotFound
} }
err = json.Unmarshal([]byte(headerStr), &route.Headers) json.Unmarshal([]byte(headerStr), &route.Headers)
json.Unmarshal([]byte(configStr), &route.Config)
return err return err
} }
func getRoute(qr rowQuerier, routeName string) (*models.Route, error) { func getRoute(qr rowQuerier, routePath string) (*models.Route, error) {
var route models.Route var route models.Route
row := qr.QueryRow(fmt.Sprintf("%s WHERE name=$1", routeSelector), routeName) row := qr.QueryRow(fmt.Sprintf("%s WHERE name=$1", routeSelector), routePath)
err := scanRoute(row, &route) err := scanRoute(row, &route)
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
@@ -234,8 +253,8 @@ func getRoute(qr rowQuerier, routeName string) (*models.Route, error) {
return &route, nil return &route, nil
} }
func (ds *PostgresDatastore) GetRoute(appName, routeName string) (*models.Route, error) { func (ds *PostgresDatastore) GetRoute(appName, routePath string) (*models.Route, error) {
return getRoute(ds.db, routeName) return getRoute(ds.db, routePath)
} }
func (ds *PostgresDatastore) GetRoutes(filter *models.RouteFilter) ([]*models.Route, error) { func (ds *PostgresDatastore) GetRoutes(filter *models.RouteFilter) ([]*models.Route, error) {

View File

@@ -22,6 +22,7 @@ var (
type App struct { type App struct {
Name string `json:"name"` Name string `json:"name"`
Routes Routes `json:"routes,omitempty"` Routes Routes `json:"routes,omitempty"`
Config `json:"config"`
} }
const ( const (

View File

@@ -1,7 +1,6 @@
package models package models
type Config struct { type Config map[string]string
}
func (c *Config) Validate() error { func (c *Config) Validate() error {
return nil return nil

View File

@@ -8,11 +8,11 @@ type Datastore interface {
StoreApp(*App) (*App, error) StoreApp(*App) (*App, error)
RemoveApp(appName string) error RemoveApp(appName string) error
GetRoute(appName, routeName string) (*Route, error) GetRoute(appName, routePath string) (*Route, error)
GetRoutes(*RouteFilter) (routes []*Route, err error) GetRoutes(*RouteFilter) (routes []*Route, err error)
GetRoutesByApp(string, *RouteFilter) (routes []*Route, err error) GetRoutesByApp(string, *RouteFilter) (routes []*Route, err error)
StoreRoute(*Route) (*Route, error) StoreRoute(*Route) (*Route, error)
RemoveRoute(appName, routeName string) error RemoveRoute(appName, routePath string) error
// The following provide a generic key value store for arbitrary data, can be used by extensions to store extra data // The following provide a generic key value store for arbitrary data, can be used by extensions to store extra data
// todo: should we namespace these by app? Then when an app is deleted, it can delete any of this extra data too. // todo: should we namespace these by app? Then when an app is deleted, it can delete any of this extra data too.
@@ -22,7 +22,7 @@ type Datastore interface {
var ( var (
ErrDatastoreEmptyAppName = errors.New("Missing app name") ErrDatastoreEmptyAppName = errors.New("Missing app name")
ErrDatastoreEmptyRouteName = errors.New("Missing route name") ErrDatastoreEmptyRoutePath = errors.New("Missing route name")
ErrDatastoreEmptyApp = errors.New("Missing app") ErrDatastoreEmptyApp = errors.New("Missing app")
ErrDatastoreEmptyRoute = errors.New("Missing route") ErrDatastoreEmptyRoute = errors.New("Missing route")
) )

View File

@@ -25,6 +25,7 @@ type Route struct {
Path string `json:"path,omitempty"` Path string `json:"path,omitempty"`
Image string `json:"image,omitempty"` Image string `json:"image,omitempty"`
Headers http.Header `json:"headers,omitempty"` Headers http.Header `json:"headers,omitempty"`
Config `json:"config"`
} }
var ( var (

View File

@@ -11,7 +11,7 @@ import (
) )
func TestAppCreate(t *testing.T) { func TestAppCreate(t *testing.T) {
New(&models.Config{}, &datastore.Mock{}, testRunner(t)) New(&datastore.Mock{}, testRunner(t))
router := testRouter() router := testRouter()
for i, test := range []struct { for i, test := range []struct {
@@ -52,7 +52,7 @@ func TestAppCreate(t *testing.T) {
} }
func TestAppDelete(t *testing.T) { func TestAppDelete(t *testing.T) {
New(&models.Config{}, &datastore.Mock{}, testRunner(t)) New(&datastore.Mock{}, testRunner(t))
router := testRouter() router := testRouter()
for i, test := range []struct { for i, test := range []struct {
@@ -83,7 +83,7 @@ func TestAppDelete(t *testing.T) {
} }
func TestAppList(t *testing.T) { func TestAppList(t *testing.T) {
New(&models.Config{}, &datastore.Mock{}, testRunner(t)) New(&datastore.Mock{}, testRunner(t))
router := testRouter() router := testRouter()
for i, test := range []struct { for i, test := range []struct {
@@ -113,7 +113,7 @@ func TestAppList(t *testing.T) {
} }
func TestAppGet(t *testing.T) { func TestAppGet(t *testing.T) {
New(&models.Config{}, &datastore.Mock{}, testRunner(t)) New(&datastore.Mock{}, testRunner(t))
router := testRouter() router := testRouter()
for i, test := range []struct { for i, test := range []struct {
@@ -143,7 +143,7 @@ func TestAppGet(t *testing.T) {
} }
func TestAppUpdate(t *testing.T) { func TestAppUpdate(t *testing.T) {
New(&models.Config{}, &datastore.Mock{}, testRunner(t)) New(&datastore.Mock{}, testRunner(t))
router := testRouter() router := testRouter()
for i, test := range []struct { for i, test := range []struct {

View File

@@ -14,34 +14,30 @@ func handleAppUpdate(c *gin.Context) {
ctx := c.MustGet("ctx").(context.Context) ctx := c.MustGet("ctx").(context.Context)
log := titancommon.Logger(ctx) log := titancommon.Logger(ctx)
app := &models.App{} wapp := models.AppWrapper{}
err := c.BindJSON(app) err := c.BindJSON(&wapp)
if err != nil { if err != nil {
log.WithError(err).Debug(models.ErrInvalidJSON) log.WithError(err).Debug(models.ErrInvalidJSON)
c.JSON(http.StatusBadRequest, simpleError(models.ErrInvalidJSON)) c.JSON(http.StatusBadRequest, simpleError(models.ErrInvalidJSON))
return return
} }
if app == nil { if wapp.App == nil {
log.Debug(models.ErrAppsMissingNew) log.Debug(models.ErrAppsMissingNew)
c.JSON(http.StatusBadRequest, simpleError(models.ErrAppsMissingNew)) c.JSON(http.StatusBadRequest, simpleError(models.ErrAppsMissingNew))
return return
} }
if err := app.Validate(); err != nil { app, err := Api.Datastore.StoreApp(wapp.App)
log.Error(err) if err != nil {
c.JSON(http.StatusInternalServerError, simpleError(err)) log.WithError(err).Debug(models.ErrAppsCreate)
c.JSON(http.StatusInternalServerError, simpleError(models.ErrAppsCreate))
return return
} }
// app, err := Api.Datastore.StoreApp(wapp.App) wapp.App = app
// if err != nil {
// log.WithError(err).Debug(models.ErrAppsCreate)
// c.JSON(http.StatusInternalServerError, simpleError(models.ErrAppsCreate))
// return
// }
// Nothing to update right now in apps // Nothing to update right now in apps
c.JSON(http.StatusOK, simpleError(models.ErrAppsNothingToUpdate)) c.JSON(http.StatusOK, appResponse{"App successfully updated", wapp})
} }

View File

@@ -15,8 +15,8 @@ func handleRouteDelete(c *gin.Context) {
log := titancommon.Logger(ctx) log := titancommon.Logger(ctx)
appName := c.Param("app") appName := c.Param("app")
routeName := c.Param("route") routePath := c.Param("route")
err := Api.Datastore.RemoveRoute(appName, routeName) err := Api.Datastore.RemoveRoute(appName, routePath)
if err != nil { if err != nil {
log.WithError(err).Debug(models.ErrRoutesRemoving) log.WithError(err).Debug(models.ErrRoutesRemoving)

View File

@@ -16,9 +16,9 @@ func handleRouteGet(c *gin.Context) {
log := titancommon.Logger(ctx) log := titancommon.Logger(ctx)
appName := c.Param("app") appName := c.Param("app")
routeName := c.Param("route") routePath := c.Param("route")
route, err := Api.Datastore.GetRoute(appName, routeName) route, err := Api.Datastore.GetRoute(appName, routePath)
if err != nil { if err != nil {
log.WithError(err).Error(models.ErrRoutesGet) log.WithError(err).Error(models.ErrRoutesGet)
c.JSON(http.StatusInternalServerError, simpleError(models.ErrRoutesGet)) c.JSON(http.StatusInternalServerError, simpleError(models.ErrRoutesGet))