diff --git a/api/datastore/bolt/bolt.go b/api/datastore/bolt/bolt.go index ac40e412a..ad5f28501 100644 --- a/api/datastore/bolt/bolt.go +++ b/api/datastore/bolt/bolt.go @@ -260,10 +260,10 @@ func (ds *BoltDatastore) GetRoute(appName, routeName string) (*models.Route, err return route, err } -func (ds *BoltDatastore) GetRoutes(filter *models.RouteFilter) ([]*models.Route, error) { +func (ds *BoltDatastore) GetRoutesByApp(appName string, filter *models.RouteFilter) ([]*models.Route, error) { res := []*models.Route{} err := ds.db.View(func(tx *bolt.Tx) error { - b, err := ds.getRouteBucketForApp(tx, filter.AppName) + b, err := ds.getRouteBucketForApp(tx, appName) if err != nil { return err } @@ -294,6 +294,43 @@ func (ds *BoltDatastore) GetRoutes(filter *models.RouteFilter) ([]*models.Route, return res, nil } +func (ds *BoltDatastore) GetRoutes(filter *models.RouteFilter) ([]*models.Route, error) { + res := []*models.Route{} + err := ds.db.View(func(tx *bolt.Tx) error { + i := 0 + rbucket := tx.Bucket(ds.routesBucket) + + b := rbucket.Cursor() + var k, v []byte + k, v = b.First() + + // Iterates all buckets + for ; k != nil && v == nil; k, v = b.Next() { + bucket := rbucket.Bucket(k) + r := bucket.Cursor() + var k2, v2 []byte + k2, v2 = r.Last() + // Iterate all routes + for ; k2 != nil; k2, v2 = r.Prev() { + var route models.Route + err := json.Unmarshal(v2, &route) + if err != nil { + return err + } + if models.ApplyRouteFilter(&route, filter) { + i++ + res = append(res, &route) + } + } + } + return nil + }) + if err != nil { + return nil, err + } + return res, nil +} + func (ds *BoltDatastore) Put(key, value []byte) error { ds.db.Update(func(tx *bolt.Tx) error { b := tx.Bucket(ds.extrasBucket) // todo: maybe namespace by app? diff --git a/api/datastore/bolt_test.go b/api/datastore/bolt_test.go index 3672b169d..e4a7263e0 100644 --- a/api/datastore/bolt_test.go +++ b/api/datastore/bolt_test.go @@ -122,7 +122,19 @@ func TestBolt(t *testing.T) { } // Testing list routes - routes, err := ds.GetRoutes(&models.RouteFilter{AppName: testApp.Name}) + routes, err := ds.GetRoutesByApp(testApp.Name, &models.RouteFilter{}) + if err != nil { + t.Fatalf("Test GetRoutes: error: %s", err) + } + if len(routes) == 0 { + t.Fatal("Test GetRoutes: expected result count to be greater than 0") + } + if routes[0].Path != testRoute.Path { + t.Fatalf("Test GetRoutes: expected `app.Name` to be `%s` but it was `%s`", testRoute.Path, routes[0].Path) + } + + // Testing list routes + routes, err = ds.GetRoutes(&models.RouteFilter{Image: testRoute.Image}) if err != nil { t.Fatalf("Test GetRoutes: error: %s", err) } diff --git a/api/datastore/mock.go b/api/datastore/mock.go index 2a2b790d7..960d6c46f 100644 --- a/api/datastore/mock.go +++ b/api/datastore/mock.go @@ -33,6 +33,10 @@ func (m *Mock) GetRoutes(routeFilter *models.RouteFilter) ([]*models.Route, erro return m.FakeRoutes, nil } +func (m *Mock) GetRoutesByApp(appName string, routeFilter *models.RouteFilter) ([]*models.Route, error) { + return m.FakeRoutes, nil +} + func (m *Mock) StoreRoute(route *models.Route) (*models.Route, error) { return m.FakeRoute, nil } diff --git a/api/datastore/postgres/postgres.go b/api/datastore/postgres/postgres.go index ffa6b962b..060de4579 100644 --- a/api/datastore/postgres/postgres.go +++ b/api/datastore/postgres/postgres.go @@ -263,6 +263,32 @@ func (ds *PostgresDatastore) GetRoutes(filter *models.RouteFilter) ([]*models.Ro return res, nil } +func (ds *PostgresDatastore) GetRoutesByApp(appName string, filter *models.RouteFilter) ([]*models.Route, error) { + res := []*models.Route{} + filter.AppName = appName + filterQuery := buildFilterQuery(filter) + rows, err := ds.db.Query(fmt.Sprintf("%s %s", routeSelector, filterQuery)) + // todo: check for no rows so we don't respond with a sql 500 err + if err != nil { + return nil, err + } + defer rows.Close() + + for rows.Next() { + var route models.Route + err := scanRoute(rows, &route) + if err != nil { + return nil, err + } + res = append(res, &route) + + } + if err := rows.Err(); err != nil { + return nil, err + } + return res, nil +} + func buildFilterQuery(filter *models.RouteFilter) string { filterQuery := "" diff --git a/api/models/datastore.go b/api/models/datastore.go index 81a63f1bd..0c195e80d 100644 --- a/api/models/datastore.go +++ b/api/models/datastore.go @@ -10,6 +10,7 @@ type Datastore interface { GetRoute(appName, routeName string) (*Route, error) GetRoutes(*RouteFilter) (routes []*Route, err error) + GetRoutesByApp(string, *RouteFilter) (routes []*Route, err error) StoreRoute(*Route) (*Route, error) RemoveRoute(appName, routeName string) error diff --git a/api/server/routes_list.go b/api/server/routes_list.go index dc1423952..5837f49f2 100644 --- a/api/server/routes_list.go +++ b/api/server/routes_list.go @@ -15,17 +15,20 @@ func handleRouteList(c *gin.Context) { ctx := c.MustGet("ctx").(context.Context) log := titancommon.Logger(ctx) - appName := c.Param("app") - - filter := &models.RouteFilter{ - AppName: appName, - } + filter := &models.RouteFilter{} if img := c.Query("image"); img != "" { filter.Image = img } - routes, err := Api.Datastore.GetRoutes(filter) + var routes []*models.Route + var err error + if app := c.Param("app"); app != "" { + routes, err = Api.Datastore.GetRoutesByApp(app, filter) + } else { + routes, err = Api.Datastore.GetRoutes(filter) + } + if err != nil { log.WithError(err).Error(models.ErrRoutesGet) c.JSON(http.StatusInternalServerError, simpleError(models.ErrRoutesGet)) diff --git a/api/server/runner.go b/api/server/runner.go index 4c6cd3fe8..ba9e2f739 100644 --- a/api/server/runner.go +++ b/api/server/runner.go @@ -88,13 +88,12 @@ func handleRunner(c *gin.Context) { } filter := &models.RouteFilter{ - Path: route, - AppName: appName, + Path: route, } log.WithFields(logrus.Fields{"app": appName, "path": route}).Debug("Finding route on datastore") - routes, err := Api.Datastore.GetRoutes(filter) + routes, err := Api.Datastore.GetRoutesByApp(appName, filter) if err != nil { log.WithError(err).Error(models.ErrRoutesList) c.JSON(http.StatusInternalServerError, simpleError(models.ErrRoutesList)) diff --git a/api/server/server.go b/api/server/server.go index e89aff492..a08b66c36 100644 --- a/api/server/server.go +++ b/api/server/server.go @@ -113,6 +113,8 @@ func bindHandlers(engine *gin.Engine) { v1.PUT("/apps/:app", handleAppUpdate) v1.DELETE("/apps/:app", handleAppDelete) + v1.GET("/routes", handleRouteList) + apps := v1.Group("/apps/:app") { apps.GET("/routes", handleRouteList)