2020-07-08 22:09:19 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2021-04-25 22:57:05 +00:00
|
|
|
"fmt"
|
2020-07-11 21:14:45 +00:00
|
|
|
"log"
|
2020-07-16 17:05:38 +00:00
|
|
|
"time"
|
2020-07-08 22:09:19 +00:00
|
|
|
|
|
|
|
"github.com/labstack/echo"
|
2021-04-25 22:57:05 +00:00
|
|
|
"github.com/nats-io/nats.go"
|
2021-10-02 18:00:35 +00:00
|
|
|
"github.com/rosti-cz/node-api/apps"
|
2021-11-01 00:17:35 +00:00
|
|
|
"github.com/rosti-cz/node-api/apps/drivers"
|
2020-07-13 22:01:42 +00:00
|
|
|
"github.com/rosti-cz/node-api/common"
|
2020-07-21 21:11:56 +00:00
|
|
|
"github.com/rosti-cz/node-api/node"
|
2020-07-08 22:09:19 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// JSONIndent Indendation of JSON output format
|
|
|
|
const JSONIndent = " "
|
|
|
|
|
2021-04-25 22:57:05 +00:00
|
|
|
var config common.Config
|
|
|
|
var nc *nats.Conn
|
2021-11-01 00:17:35 +00:00
|
|
|
var snapshotProcessor apps.SnapshotProcessor
|
2021-04-25 22:57:05 +00:00
|
|
|
|
|
|
|
func _init() {
|
|
|
|
var err error
|
|
|
|
|
|
|
|
// Load config from environment variables
|
|
|
|
config = *common.GetConfig()
|
|
|
|
|
|
|
|
// Connect to the NATS service
|
|
|
|
nc, err = nats.Connect(config.NATSURL)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalln(err)
|
|
|
|
}
|
2021-10-02 18:00:35 +00:00
|
|
|
|
|
|
|
// Database migrations
|
|
|
|
processor := apps.AppsProcessor{
|
|
|
|
DB: common.GetDBConnection(),
|
|
|
|
}
|
|
|
|
processor.Init()
|
2021-11-01 00:17:35 +00:00
|
|
|
|
|
|
|
// Prepare snapshot processor
|
|
|
|
snapshotProcessor = apps.SnapshotProcessor{
|
|
|
|
AppsPath: config.AppsPath,
|
|
|
|
TmpSnapshotPath: config.SnapshotsPath,
|
|
|
|
IndexLabel: config.SnapshotsIndexLabel,
|
|
|
|
|
|
|
|
Driver: drivers.S3Driver{
|
|
|
|
S3AccessKey: config.SnapshotsS3AccessKey,
|
|
|
|
S3SecretKey: config.SnapshotsS3SecretKey,
|
|
|
|
S3Endpoint: config.SnapshotsS3Endpoint,
|
|
|
|
S3SSL: config.SnapshotsS3SSL,
|
|
|
|
Bucket: config.SnapshotsS3Bucket,
|
|
|
|
},
|
|
|
|
}
|
2021-04-25 22:57:05 +00:00
|
|
|
}
|
|
|
|
|
2020-07-08 22:09:19 +00:00
|
|
|
func main() {
|
2021-04-25 22:57:05 +00:00
|
|
|
_init()
|
|
|
|
defer nc.Drain()
|
|
|
|
|
2020-07-08 22:09:19 +00:00
|
|
|
// Close database at the end
|
|
|
|
db := common.GetDBConnection()
|
|
|
|
defer db.Close()
|
|
|
|
|
2020-07-13 22:01:42 +00:00
|
|
|
// Templating
|
|
|
|
t := &Template{}
|
|
|
|
|
2020-07-16 17:05:38 +00:00
|
|
|
// Stats loop
|
|
|
|
go func() {
|
2020-07-21 21:11:56 +00:00
|
|
|
for {
|
2021-04-02 16:10:34 +00:00
|
|
|
log.Println("Stats gathering started")
|
|
|
|
start := time.Now()
|
2020-07-25 22:34:16 +00:00
|
|
|
err := gatherStats()
|
2020-07-21 21:11:56 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Println("LOOP ERROR:", err.Error())
|
|
|
|
}
|
2021-04-02 16:10:34 +00:00
|
|
|
elapsed := time.Since(start)
|
|
|
|
log.Printf("Stats gathering elapsed time: %.2fs\n", elapsed.Seconds())
|
2021-04-25 22:57:05 +00:00
|
|
|
time.Sleep(300 * time.Second)
|
2020-07-21 21:11:56 +00:00
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
// Node stats
|
|
|
|
go func() {
|
|
|
|
for {
|
|
|
|
err := node.Log()
|
|
|
|
if err != nil {
|
|
|
|
log.Println("NODE PERFORMANCE LOG ERROR:", err.Error())
|
|
|
|
}
|
|
|
|
time.Sleep(5 * time.Minute)
|
2020-07-16 17:05:38 +00:00
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
2020-07-08 22:09:19 +00:00
|
|
|
// API
|
|
|
|
e := echo.New()
|
2020-07-13 22:01:42 +00:00
|
|
|
e.Renderer = t
|
|
|
|
|
2020-08-29 13:12:29 +00:00
|
|
|
e.Use(TokenMiddleware)
|
2020-07-08 22:09:19 +00:00
|
|
|
|
2021-04-25 22:57:05 +00:00
|
|
|
// NATS handling
|
|
|
|
// admin.apps.ALIAS.events
|
|
|
|
// admin.apps.ALIAS.states
|
|
|
|
subjectEvents := fmt.Sprintf("admin.apps.%s.requests", config.NATSAlias)
|
|
|
|
log.Println("> listening on " + subjectEvents)
|
|
|
|
nc.Subscribe(subjectEvents, messageHandler)
|
|
|
|
|
2020-08-23 00:08:05 +00:00
|
|
|
// UI
|
|
|
|
e.GET("/", homeHandler)
|
2020-07-08 22:09:19 +00:00
|
|
|
|
2021-04-02 16:27:57 +00:00
|
|
|
// Prometheus metrics
|
|
|
|
e.GET("/metrics", metricsHandler)
|
|
|
|
|
2020-08-23 00:08:05 +00:00
|
|
|
// Returns list of apps
|
|
|
|
e.GET("/v1/apps", listAppsHandler)
|
2020-07-08 22:09:19 +00:00
|
|
|
|
|
|
|
// Returns one app
|
2020-08-23 00:08:05 +00:00
|
|
|
e.GET("/v1/apps/:name", getAppHandler)
|
2020-07-08 22:09:19 +00:00
|
|
|
|
|
|
|
// Create a new app
|
2020-08-18 20:52:34 +00:00
|
|
|
// If you add register_only=1 into query string, it won't start or create any container, just adds record into the database.
|
2020-08-23 00:08:05 +00:00
|
|
|
e.POST("/v1/apps", createAppHandler)
|
2020-07-08 22:09:19 +00:00
|
|
|
|
|
|
|
// Update existing app
|
2020-08-23 00:08:05 +00:00
|
|
|
e.PUT("/v1/apps/:name", updateAppHandler)
|
2020-07-08 22:09:19 +00:00
|
|
|
|
|
|
|
// Stop existing app
|
2020-08-23 00:08:05 +00:00
|
|
|
e.PUT("/v1/apps/:name/stop", stopAppHandler)
|
2020-07-08 22:09:19 +00:00
|
|
|
|
|
|
|
// Start existing app
|
2020-08-23 00:08:05 +00:00
|
|
|
e.PUT("/v1/apps/:name/start", startAppHandler)
|
2020-07-08 22:09:19 +00:00
|
|
|
|
|
|
|
// Stop existing app
|
2020-08-23 00:08:05 +00:00
|
|
|
e.PUT("/v1/apps/:name/restart", restartAppHandler)
|
2020-07-11 21:14:45 +00:00
|
|
|
|
2020-08-23 00:08:05 +00:00
|
|
|
// Application processes
|
|
|
|
e.GET("/v1/apps/:name/processes", getAppProcessesHandler)
|
2020-07-08 22:09:19 +00:00
|
|
|
|
2020-08-06 22:36:40 +00:00
|
|
|
// Set password for the app user in the container
|
2020-08-23 00:08:05 +00:00
|
|
|
e.PUT("/v1/apps/:name/password", setPasswordHandler)
|
2020-08-06 22:36:40 +00:00
|
|
|
|
|
|
|
// Copies body of the request into /srv/.ssh/authorized_keys
|
2020-08-23 00:08:05 +00:00
|
|
|
e.PUT("/v1/apps/:name/keys", setKeysHandler)
|
2020-08-20 23:00:24 +00:00
|
|
|
|
2021-04-25 22:57:05 +00:00
|
|
|
// Enable one of the supported technologies or services (python, node, redis, ...)
|
2020-08-23 00:08:05 +00:00
|
|
|
e.PUT("/v1/apps/:name/set-services", setServicesHandler)
|
2020-08-20 23:00:24 +00:00
|
|
|
|
2021-04-25 22:57:05 +00:00
|
|
|
// Rebuilds existing app, it keeps the data but creates the container again
|
2020-08-23 00:08:05 +00:00
|
|
|
e.PUT("/v1/apps/:name/rebuild", rebuildAppHandler)
|
2020-07-08 22:09:19 +00:00
|
|
|
|
2020-07-16 21:24:09 +00:00
|
|
|
// Adds new label
|
2020-08-23 00:08:05 +00:00
|
|
|
e.POST("/v1/apps/:name/labels", addLabelHandler)
|
2020-07-16 21:24:09 +00:00
|
|
|
|
|
|
|
// Removes existing label
|
2020-08-23 00:08:05 +00:00
|
|
|
e.DELETE("/v1/apps/:name/labels", deleteLabelHandler)
|
2020-07-16 21:24:09 +00:00
|
|
|
|
2020-07-08 22:09:19 +00:00
|
|
|
// Delete one app
|
2020-08-23 00:08:05 +00:00
|
|
|
e.DELETE("/v1/apps/:name", deleteAppHandler)
|
2020-07-08 22:09:19 +00:00
|
|
|
|
2020-07-13 22:01:42 +00:00
|
|
|
// Orphans returns directories in /srv that doesn't match any hosted application
|
2020-08-23 00:08:05 +00:00
|
|
|
e.GET("/v1/orphans", getOrphansHander)
|
2020-07-13 22:01:42 +00:00
|
|
|
|
2020-07-08 22:09:19 +00:00
|
|
|
// Return info about the node including performance index
|
2020-08-23 00:08:05 +00:00
|
|
|
e.GET("/v1/node", getNodeInfoHandler)
|
2020-07-08 22:09:19 +00:00
|
|
|
|
2021-10-02 18:00:35 +00:00
|
|
|
err := e.Start(":1323")
|
|
|
|
|
|
|
|
// fmt.Println(err.Error())
|
|
|
|
// if strings.Contains(err.Error(), "SIGTERM") {
|
|
|
|
// e.Logger.Info(err)
|
|
|
|
// os.Exit(0)
|
|
|
|
// }
|
|
|
|
|
|
|
|
e.Logger.Fatal(err)
|
2020-07-08 22:09:19 +00:00
|
|
|
}
|