node-api/main.go

214 lines
5.0 KiB
Go
Raw Permalink Normal View History

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
2024-01-26 17:46:19 +00:00
"github.com/getsentry/sentry-go"
sentryecho "github.com/getsentry/sentry-go/echo"
"github.com/labstack/echo/v4"
2021-04-25 22:57:05 +00:00
"github.com/nats-io/nats.go"
"github.com/rosti-cz/node-api/apps"
"github.com/rosti-cz/node-api/apps/drivers"
2020-07-13 22:01:42 +00:00
"github.com/rosti-cz/node-api/common"
"github.com/rosti-cz/node-api/glue"
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
var snapshotProcessor apps.SnapshotProcessor
var nodeProcessor node.Processor
2021-04-25 22:57:05 +00:00
2022-05-06 16:59:58 +00:00
var elapsedMetric int // time elapsed while loading stats about apps
2021-04-25 22:57:05 +00:00
func _init() {
var err error
// Load config from environment variables
config = *common.GetConfig()
2024-01-26 17:46:19 +00:00
// Sentry
sentry.Init(sentry.ClientOptions{
Dsn: config.SentryDSN,
AttachStacktrace: true,
Environment: config.SentryENV,
TracesSampleRate: 0.1,
})
2021-04-25 22:57:05 +00:00
// Connect to the NATS service
nc, err = nats.Connect(config.NATSURL)
if err != nil {
2024-01-26 20:15:14 +00:00
sentry.CaptureException(err)
2021-04-25 22:57:05 +00:00
log.Fatalln(err)
}
// Database migrations
processor := apps.AppsProcessor{
DB: common.GetDBConnection(),
}
processor.Init()
// 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,
},
}
nodeProcessor = node.Processor{
DB: common.GetDBConnection(),
}
nodeProcessor.Init()
2022-05-06 16:59:58 +00:00
// Reset elapsed stats
elapsedMetric = -1
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()
2024-01-26 17:46:19 +00:00
defer sentry.Flush(time.Second * 10)
2021-04-25 22:57:05 +00:00
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() {
statsProcessor := glue.StatsProcessor{
2022-02-07 16:12:23 +00:00
DB: common.GetDBConnection(),
DockerSock: config.DockerSocket,
2022-02-07 16:18:44 +00:00
BindIPHTTP: config.AppsBindIPHTTP,
BindIPSSH: config.AppsBindIPSSH,
AppsPath: config.AppsPath,
}
for {
log.Println("Stats gathering started")
start := time.Now()
err := statsProcessor.GatherStats()
if err != nil {
2024-01-26 20:15:14 +00:00
sentry.CaptureException(err)
log.Println("LOOP ERROR:", err.Error())
}
elapsed := time.Since(start)
2022-05-06 16:59:58 +00:00
elapsedMetric = int(elapsed)
log.Printf("Stats gathering elapsed time: %.2fs\n", elapsed.Seconds())
time.Sleep(300 * time.Second)
}
}()
2020-07-21 21:11:56 +00:00
// Node stats
go func() {
for {
err := nodeProcessor.Log()
2020-07-21 21:11:56 +00:00
if err != nil {
2024-01-26 20:15:14 +00:00
sentry.CaptureException(err)
2020-07-21 21:11:56 +00:00
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
e.Use(TokenMiddleware)
2024-01-26 17:46:19 +00:00
e.Use(sentryecho.New(sentryecho.Options{}))
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)
// 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)
// Returns list of apps
e.GET("/v1/apps", listAppsHandler)
2020-07-08 22:09:19 +00:00
// Returns one app
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.
e.POST("/v1/apps", createAppHandler)
2020-07-08 22:09:19 +00:00
// Update existing app
e.PUT("/v1/apps/:name", updateAppHandler)
2020-07-08 22:09:19 +00:00
// Stop existing app
e.PUT("/v1/apps/:name/stop", stopAppHandler)
2020-07-08 22:09:19 +00:00
// Start existing app
e.PUT("/v1/apps/:name/start", startAppHandler)
2020-07-08 22:09:19 +00:00
// Stop existing app
e.PUT("/v1/apps/:name/restart", restartAppHandler)
2020-07-11 21:14:45 +00:00
// Application processes
e.GET("/v1/apps/:name/processes", getAppProcessesHandler)
2020-07-08 22:09:19 +00:00
// Set password for the app user in the container
e.PUT("/v1/apps/:name/password", setPasswordHandler)
// Copies body of the request into /srv/.ssh/authorized_keys
e.PUT("/v1/apps/:name/keys", setKeysHandler)
2021-04-25 22:57:05 +00:00
// Enable one of the supported technologies or services (python, node, redis, ...)
e.PUT("/v1/apps/:name/set-services", setServicesHandler)
2021-04-25 22:57:05 +00:00
// Rebuilds existing app, it keeps the data but creates the container again
e.PUT("/v1/apps/:name/rebuild", rebuildAppHandler)
2020-07-08 22:09:19 +00:00
2024-01-30 22:50:03 +00:00
// Save metadata about app
2024-01-30 22:52:33 +00:00
e.POST("/v1/apps/:name/metadata", saveMetadataHandler)
2024-01-30 22:50:03 +00:00
2020-07-16 21:24:09 +00:00
// Adds new label
e.POST("/v1/apps/:name/labels", addLabelHandler)
2020-07-16 21:24:09 +00:00
// Removes existing label
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
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
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
e.GET("/v1/node", getNodeInfoHandler)
2020-07-08 22:09:19 +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
}