package main import ( "log" "net/http" "github.com/labstack/echo" "github.com/rosti-cz/node-api/apps" "github.com/rosti-cz/node-api/common" "github.com/rosti-cz/node-api/docker" "github.com/rosti-cz/node-api/nodes" ) // JSONIndent Indendation of JSON output format const JSONIndent = " " func main() { // Close database at the end db := common.GetDBConnection() // db.AutoMigrate(apps.Label{}) // db.AutoMigrate(apps.App{}) defer db.Close() // Templating t := &Template{} // API e := echo.New() e.Renderer = t // e.Use(TokenMiddleware) // Returns list of apps e.GET("/", func(c echo.Context) error { return c.Render(http.StatusOK, "index.html", "") }) e.GET("/v1/apps", func(c echo.Context) error { applications, err := apps.List() if err != nil { return c.JSONPretty(http.StatusInternalServerError, Message{Message: err.Error()}, JSONIndent) } populatedApps := []*apps.App{} for _, app := range *applications { container := docker.Container{ App: &app, } populatedApp, err := container.GetApp() if err != nil { return c.JSONPretty(http.StatusInternalServerError, Message{Message: err.Error()}, JSONIndent) } populatedApps = append(populatedApps, populatedApp) } return c.JSON(http.StatusOK, populatedApps) }) // Returns one app e.GET("/v1/apps/:name", func(c echo.Context) error { name := c.Param("name") app, err := apps.Get(name) if err != nil { return c.JSONPretty(http.StatusInternalServerError, Message{Message: err.Error()}, JSONIndent) } container := docker.Container{ App: app, } _, err = container.GetApp() if err != nil { return c.JSONPretty(http.StatusInternalServerError, Message{Message: err.Error()}, JSONIndent) } return c.JSON(http.StatusOK, app) }) // Create a new app e.POST("/v1/apps", func(c echo.Context) error { app := apps.App{} err := c.Bind(&app) if err != nil { return c.JSONPretty(http.StatusBadRequest, Message{Message: err.Error()}, JSONIndent) } err = apps.New(app.Name, app.SSHPort, app.HTTPPort, app.Image, app.CPU, app.Memory) if err != nil { if validationError, ok := err.(apps.ValidationError); ok { return c.JSONPretty(http.StatusBadRequest, Message{Errors: validationError.Errors}, JSONIndent) } return c.JSONPretty(http.StatusInternalServerError, Message{Message: err.Error()}, JSONIndent) } container := docker.Container{ App: &app, } err = container.Create() if err != nil { return c.JSONPretty(http.StatusInternalServerError, Message{Message: err.Error()}, JSONIndent) } err = container.Start() if err != nil { return c.JSONPretty(http.StatusInternalServerError, Message{Message: err.Error()}, JSONIndent) } return c.JSON(http.StatusOK, Message{Message: "ok"}) }) // Update existing app e.PUT("/v1/apps/:name", func(c echo.Context) error { name := c.Param("name") app := apps.App{} err := c.Bind(&app) if err != nil { return c.JSONPretty(http.StatusBadRequest, Message{Message: err.Error()}, JSONIndent) } appPointer, err := apps.Update(name, app.SSHPort, app.HTTPPort, app.Image, app.CPU, app.Memory) if err != nil { if validationError, ok := err.(apps.ValidationError); ok { return c.JSONPretty(http.StatusBadRequest, Message{Errors: validationError.Errors}, JSONIndent) } return c.JSONPretty(http.StatusInternalServerError, Message{Message: err.Error()}, JSONIndent) } app = *appPointer container := docker.Container{ App: &app, } err = container.Destroy() if err != nil { return c.JSONPretty(http.StatusInternalServerError, Message{Message: err.Error()}, JSONIndent) } err = container.Create() if err != nil { return c.JSONPretty(http.StatusInternalServerError, Message{Message: err.Error()}, JSONIndent) } err = container.Start() if err != nil { return c.JSONPretty(http.StatusInternalServerError, Message{Message: err.Error()}, JSONIndent) } return c.JSON(http.StatusOK, map[string]string{}) }) // Stop existing app e.PUT("/v1/apps/:name/stop", func(c echo.Context) error { name := c.Param("name") app, err := apps.Get(name) if err != nil { return c.JSONPretty(http.StatusInternalServerError, Message{Message: err.Error()}, JSONIndent) } container := docker.Container{ App: app, } err = container.Stop() if err != nil { return c.JSONPretty(http.StatusInternalServerError, Message{Message: err.Error()}, JSONIndent) } return c.JSON(http.StatusOK, Message{Message: "ok"}) }) // Start existing app e.PUT("/v1/apps/:name/start", func(c echo.Context) error { name := c.Param("name") app, err := apps.Get(name) if err != nil { return c.JSONPretty(http.StatusInternalServerError, Message{Message: err.Error()}, JSONIndent) } container := docker.Container{ App: app, } err = container.Start() if err != nil { return c.JSONPretty(http.StatusInternalServerError, Message{Message: err.Error()}, JSONIndent) } return c.JSON(http.StatusOK, Message{Message: "ok"}) }) // Stop existing app e.PUT("/v1/apps/:name/restart", func(c echo.Context) error { name := c.Param("name") app, err := apps.Get(name) if err != nil { return c.JSONPretty(http.StatusInternalServerError, Message{Message: err.Error()}, JSONIndent) } container := docker.Container{ App: app, } err = container.Restart() if err != nil { return c.JSONPretty(http.StatusInternalServerError, Message{Message: err.Error()}, JSONIndent) } return c.JSON(http.StatusOK, Message{Message: "ok"}) }) // Stats for existing app e.GET("/v1/apps/:name/stats", func(c echo.Context) error { name := c.Param("name") app, err := apps.Get(name) if err != nil { return c.JSONPretty(http.StatusInternalServerError, Message{Message: err.Error()}, JSONIndent) } container := docker.Container{ App: app, } cpu, memory, err := container.ResourceUsage() if err != nil { return c.JSONPretty(http.StatusInternalServerError, Message{Message: err.Error()}, JSONIndent) } log.Println("DEBUG", cpu, memory) return c.JSON(http.StatusOK, Message{Message: "ok"}) }) // Rebuilds existing app, it keeps the data but created the container again e.PUT("/v1/apps/:name/rebuild", func(c echo.Context) error { name := c.Param("name") app, err := apps.Get(name) if err != nil { return c.JSONPretty(http.StatusInternalServerError, Message{Message: err.Error()}, JSONIndent) } container := docker.Container{ App: app, } err = container.Destroy() if err != nil && err.Error() == "no container found" { // We don't care if the container didn't exist anyway err = nil } if err != nil { return c.JSONPretty(http.StatusInternalServerError, Message{Message: err.Error()}, JSONIndent) } err = container.Create() if err != nil { return c.JSONPretty(http.StatusInternalServerError, Message{Message: err.Error()}, JSONIndent) } return c.JSON(http.StatusOK, Message{Message: "ok"}) }) // Delete one app e.DELETE("/v1/apps/:name", func(c echo.Context) error { name := c.Param("name") app, err := apps.Get(name) if err != nil { return c.JSONPretty(http.StatusInternalServerError, Message{Message: err.Error()}, JSONIndent) } container := docker.Container{ App: app, } err = container.Delete() if err != nil { return c.JSONPretty(http.StatusInternalServerError, Message{Message: err.Error()}, JSONIndent) } err = apps.Delete(name) if err != nil { return c.JSONPretty(http.StatusInternalServerError, Message{Message: err.Error()}, JSONIndent) } return c.JSON(http.StatusOK, Message{Message: "deleted"}) }) // Orphans returns directories in /srv that doesn't match any hosted application e.GET("/v1/orphans", func(c echo.Context) error { return c.JSON(http.StatusOK, []string{}) }) // Return info about the node including performance index e.GET("/v1/node", func(c echo.Context) error { node := nodes.GetNodeInfo() return c.JSON(http.StatusOK, node) }) e.Logger.Fatal(e.Start(":1323")) }