node-api/handlers_nats.go

1127 lines
31 KiB
Go

package main
/*
Message handling is pretty straightforward. When request is received it's
usually asynchronic and the client is not waiting for an reply. In this case
client writes down that something is happening here and when it's done publish()
function is used to notify everybody that it's done. Client usually listens to
this channel and it finish his part as it needs.
In case there is a reply we use NATS's responde() method to return the data
as soon as possible.
*/
import (
"encoding/json"
"fmt"
"log"
"regexp"
"strings"
"github.com/getsentry/sentry-go"
"github.com/nats-io/nats.go"
"github.com/pkg/errors"
"github.com/rosti-cz/node-api/apps"
"github.com/rosti-cz/node-api/common"
"github.com/rosti-cz/node-api/glue"
)
// This handler only passes messages to another function for easier testing
func messageHandler(msg *nats.Msg) {
go _messageHandler(msg)
}
func _messageHandler(m *nats.Msg) error {
message := RequestMessage{}
err := json.Unmarshal(m.Data, &message)
if err != nil {
sentry.CaptureException(err)
log.Println(errors.Wrap(err, "invalid JSON data in the incoming message"))
return err
}
fmt.Printf("Received a message: %v\n", message)
eventHandlerMap := map[string](func(m *nats.Msg, message *RequestMessage) error){
"list": listEventHandler,
"get": getEventHandler,
"fast_get": fastGetEventHandler, // same as get but without status update
"create": createEventHandler,
"register": registerEventHandler,
"update": updateEventHandler,
"delete": deleteEventHandler,
"stop": stopEventHandler,
"start": startEventHandler,
"restart": restartEventHandler,
"get_deploy_ssh_keys": getDeploySSHKeysEventHandler,
"get_ssh_host_key": getSSHHostKeyEventHandler,
"get_active_tech": getActiveTechHandler,
"update_keys": updateKeysEventHandler,
"set_password": setPasswordEventHandler,
"processes": processesEventHandler,
"enable_tech": enableTechEventHandler,
"rebuild": rebuildEventHandler,
"add_label": addLabelEventHandler,
"remove_label": removeLabelEventHandler,
"list_orphans": listOrphansEventHandler,
"save_metadata": saveMetadataEventHandler,
"node": getNodeEventHandler,
"create_snapshot": createSnapshotEventHandler,
"restore_from_snapshot": restoreFromSnapshotEventHandler,
"list_snapshots": listSnapshotsEventHandler,
"list_apps_snapshots": listAppsSnapshotsEventHandler,
"list_snapshots_by_label": listSnapshotsByLabelEventHandler,
"get_snapshot": getSnapshotEventHandler,
"get_snapshot_download_link": getSnapshotDownloadLinkEventHandler,
"delete_snapshot": deleteSnapshotEventHandler,
"delete_app_snapshots": deleteAppSnapshotsEventHandler,
}
if eventHandler, ok := eventHandlerMap[message.Type]; ok {
err = eventHandler(m, &message)
if err != nil {
sentry.CaptureException(err)
}
return err
} else {
log.Println("ERROR: event handler not defined for " + message.Type)
}
// Set password for the app user in the container
// Application processes
// Enable one of the supported technologies or services (python, node, redis, ...)
// Rebuilds existing app, it keeps the data but creates the container again
// Orphans returns directories in /srv that doesn't match any hosted application
// Return info about the node including performance index
return nil
}
// Returns list of apps
func listEventHandler(m *nats.Msg, message *RequestMessage) error {
log.Println("> List")
processor := glue.Processor{
AppName: message.AppName,
DB: common.GetDBConnection(),
DockerSock: config.DockerSocket,
BindIPHTTP: config.AppsBindIPHTTP,
BindIPSSH: config.AppsBindIPSSH,
AppsPath: config.AppsPath,
}
applications, err := processor.List(false)
if err != nil {
return errorReplyFormater(m, "backend error", err)
}
reply := ReplyMessage{
Payload: applications,
}
data, err := json.Marshal(reply)
if err != nil {
return errorReplyFormater(m, "reply formatter error", err)
}
err = m.Respond(data)
if err != nil {
log.Println("ERROR: list apps:", err.Error())
}
return err
}
// Returns one app
func getEventHandler(m *nats.Msg, message *RequestMessage) error {
processor := glue.Processor{
AppName: message.AppName,
DB: common.GetDBConnection(),
DockerSock: config.DockerSocket,
BindIPHTTP: config.AppsBindIPHTTP,
BindIPSSH: config.AppsBindIPSSH,
AppsPath: config.AppsPath,
}
app, err := processor.Get(false)
if err != nil {
log.Printf("backend error: %v\n", err)
return errorReplyFormater(m, "backend error", err)
}
// Assembling reply message
reply := ReplyMessage{
AppName: app.Name,
Payload: app,
}
data, err := json.Marshal(reply)
if err != nil {
return errorReplyFormater(m, "reply formatter error", err)
}
err = m.Respond(data)
if err != nil {
log.Println("ERROR: get app:", err.Error())
}
return err
}
// Returns one app fast which means with no immediate status update
func fastGetEventHandler(m *nats.Msg, message *RequestMessage) error {
processor := glue.Processor{
AppName: message.AppName,
DB: common.GetDBConnection(),
DockerSock: config.DockerSocket,
BindIPHTTP: config.AppsBindIPHTTP,
BindIPSSH: config.AppsBindIPSSH,
AppsPath: config.AppsPath,
}
app, err := processor.Get(true)
if err != nil {
log.Printf("backend error: %v\n", err)
return errorReplyFormater(m, "backend error", err)
}
// Assembling reply message
reply := ReplyMessage{
AppName: app.Name,
Payload: app,
}
data, err := json.Marshal(reply)
if err != nil {
return errorReplyFormater(m, "reply formatter error", err)
}
err = m.Respond(data)
if err != nil {
log.Println("ERROR: get app:", err.Error())
}
return err
}
// Create a new app
func createEventHandler(m *nats.Msg, message *RequestMessage) error {
appTemplate := apps.App{}
body := []byte(message.Payload)
err := json.Unmarshal(body, &appTemplate)
if err != nil {
log.Println("ERROR create application problem (unmarshal): " + err.Error())
publish(message.AppName, "payload parsing problem", true)
return err
}
processor := glue.Processor{
AppName: message.AppName,
DB: common.GetDBConnection(),
SnapshotProcessor: &snapshotProcessor,
DockerSock: config.DockerSocket,
BindIPHTTP: config.AppsBindIPHTTP,
BindIPSSH: config.AppsBindIPSSH,
AppsPath: config.AppsPath,
}
err = processor.Create(appTemplate)
if err != nil && strings.Contains(err.Error(), "validation error") {
publish(message.AppName, "validation error", true)
return err
} else if err != nil {
log.Println("ERROR create application problem: " + err.Error())
publish(message.AppName, "backend problem", true)
return err
}
publish(message.AppName, "created", false)
return nil
}
// Registers new app without creating an container
func registerEventHandler(m *nats.Msg, message *RequestMessage) error {
appTemplate := apps.App{}
body := []byte(message.Payload)
err := json.Unmarshal(body, &appTemplate)
if err != nil {
log.Println("ERROR create application problem (Unmarshal): " + err.Error())
publish(message.AppName, "payload parsing problem", true)
return err
}
processor := glue.Processor{
AppName: message.AppName,
DB: common.GetDBConnection(),
SnapshotProcessor: &snapshotProcessor,
DockerSock: config.DockerSocket,
BindIPHTTP: config.AppsBindIPHTTP,
BindIPSSH: config.AppsBindIPSSH,
AppsPath: config.AppsPath,
}
err = processor.Register(appTemplate)
if err != nil && strings.Contains(err.Error(), "validation error") {
publish(message.AppName, "validation error", true)
return err
} else if err != nil {
log.Println("ERROR create application problem: " + err.Error())
publish(message.AppName, "backend problem", true)
return err
}
publish(message.AppName, "registered", false)
return nil
}
// Update existing app
func updateEventHandler(m *nats.Msg, message *RequestMessage) error {
appTemplate := apps.App{}
body := []byte(message.Payload)
err := json.Unmarshal(body, &appTemplate)
if err != nil {
log.Println("ERROR update application problem (unmarshal): " + err.Error())
publish(message.AppName, "payload parsing problem", true)
return err
}
// This is small inconsistency because the app name is not coming from the admin which this line fixes.
// TODO: We should probably somehow fixed this for this and all other endpoints too. Message app name and payload
// TODO: app name have to always the same.
appTemplate.Name = message.AppName
processor := glue.Processor{
AppName: message.AppName,
DB: common.GetDBConnection(),
SnapshotProcessor: &snapshotProcessor,
DockerSock: config.DockerSocket,
BindIPHTTP: config.AppsBindIPHTTP,
BindIPSSH: config.AppsBindIPSSH,
AppsPath: config.AppsPath,
}
err = processor.Update(appTemplate)
if err != nil && strings.Contains(err.Error(), "validation error") {
publish(message.AppName, "validation error", true)
return err
} else if err != nil {
log.Println("ERROR create application problem: " + err.Error())
publish(message.AppName, "backend problem", true)
return err
}
publish(message.AppName, "updated", false)
return nil
}
// Delete one app
func deleteEventHandler(m *nats.Msg, message *RequestMessage) error {
processor := glue.Processor{
AppName: message.AppName,
DB: common.GetDBConnection(),
SnapshotProcessor: &snapshotProcessor,
DockerSock: config.DockerSocket,
BindIPHTTP: config.AppsBindIPHTTP,
BindIPSSH: config.AppsBindIPSSH,
AppsPath: config.AppsPath,
}
err := processor.Delete()
if err != nil {
log.Println("ERROR delete application problem: " + err.Error())
publish(message.AppName, "backend problem", true)
return err
}
publish(message.AppName, "deleted", false)
return nil
}
// Stop existing app
func stopEventHandler(m *nats.Msg, message *RequestMessage) error {
processor := glue.Processor{
AppName: message.AppName,
DB: common.GetDBConnection(),
SnapshotProcessor: &snapshotProcessor,
DockerSock: config.DockerSocket,
BindIPHTTP: config.AppsBindIPHTTP,
BindIPSSH: config.AppsBindIPSSH,
AppsPath: config.AppsPath,
}
err := processor.Stop()
if err != nil {
log.Println("ERROR stop application problem: " + err.Error())
publish(message.AppName, "backend problem", true)
return err
}
publish(message.AppName, "stopped", false)
return nil
}
// Start existing app
func startEventHandler(m *nats.Msg, message *RequestMessage) error {
processor := glue.Processor{
AppName: message.AppName,
DB: common.GetDBConnection(),
SnapshotProcessor: &snapshotProcessor,
DockerSock: config.DockerSocket,
BindIPHTTP: config.AppsBindIPHTTP,
BindIPSSH: config.AppsBindIPSSH,
AppsPath: config.AppsPath,
}
err := processor.Start()
if err != nil {
log.Println("ERROR start application problem: " + err.Error())
publish(message.AppName, "backend problem", true)
return err
}
publish(message.AppName, "started", false)
return nil
}
// Restart existing app
func restartEventHandler(m *nats.Msg, message *RequestMessage) error {
processor := glue.Processor{
AppName: message.AppName,
DB: common.GetDBConnection(),
SnapshotProcessor: &snapshotProcessor,
DockerSock: config.DockerSocket,
BindIPHTTP: config.AppsBindIPHTTP,
BindIPSSH: config.AppsBindIPSSH,
AppsPath: config.AppsPath,
}
err := processor.Restart()
if err != nil {
log.Println("ERROR restart application problem: " + err.Error())
publish(message.AppName, "backend problem", true)
return err
}
publish(message.AppName, "restarted", false)
return nil
}
func getDeploySSHKeysEventHandler(m *nats.Msg, message *RequestMessage) error {
processor := glue.Processor{
AppName: message.AppName,
DB: common.GetDBConnection(),
SnapshotProcessor: &snapshotProcessor,
DockerSock: config.DockerSocket,
BindIPHTTP: config.AppsBindIPHTTP,
BindIPSSH: config.AppsBindIPSSH,
AppsPath: config.AppsPath,
}
privateKey, pubKey, err := processor.GenerateDeploySSHKeys()
if err != nil {
log.Printf("backend error: %v\n", err)
return errorReplyFormater(m, "backend error", err)
}
// Assembling reply message
reply := ReplyMessage{
Payload: struct {
PrivateKey string `json:"private_key"`
PublicKey string `json:"public_key"`
}{
PrivateKey: privateKey,
PublicKey: pubKey,
},
}
data, err := json.Marshal(reply)
if err != nil {
return errorReplyFormater(m, "reply formatter error", err)
}
err = m.Respond(data)
if err != nil {
log.Println("ERROR: get app:", err.Error())
return err
}
return nil
}
// Returns SSH host key
func getSSHHostKeyEventHandler(m *nats.Msg, message *RequestMessage) error {
processor := glue.Processor{
AppName: message.AppName,
DB: common.GetDBConnection(),
SnapshotProcessor: &snapshotProcessor,
DockerSock: config.DockerSocket,
BindIPHTTP: config.AppsBindIPHTTP,
BindIPSSH: config.AppsBindIPSSH,
AppsPath: config.AppsPath,
}
hostKey, err := processor.GetHostKey()
if err != nil {
log.Printf("backend error: %v\n", err)
return errorReplyFormater(m, "backend error", err)
}
// Assembling reply message
reply := ReplyMessage{
Payload: hostKey,
}
data, err := json.Marshal(reply)
if err != nil {
return errorReplyFormater(m, "reply formatter error", err)
}
err = m.Respond(data)
if err != nil {
log.Println("ERROR: get app:", err.Error())
return err
}
return nil
}
// Copies body of the request into /srv/.ssh/authorized_keys
func updateKeysEventHandler(m *nats.Msg, message *RequestMessage) error {
body := message.Payload
processor := glue.Processor{
AppName: message.AppName,
DB: common.GetDBConnection(),
SnapshotProcessor: &snapshotProcessor,
DockerSock: config.DockerSocket,
BindIPHTTP: config.AppsBindIPHTTP,
BindIPSSH: config.AppsBindIPSSH,
AppsPath: config.AppsPath,
}
err := processor.UpdateKeys(body)
if err != nil {
log.Println("ERROR update keys problem: " + err.Error())
publish(message.AppName, "backend problem", true)
return err
}
publish(message.AppName, "keys updated", false)
return nil
}
// Set password for the app user in the container
func setPasswordEventHandler(m *nats.Msg, message *RequestMessage) error {
password := message.Payload
processor := glue.Processor{
AppName: message.AppName,
DB: common.GetDBConnection(),
SnapshotProcessor: &snapshotProcessor,
DockerSock: config.DockerSocket,
BindIPHTTP: config.AppsBindIPHTTP,
BindIPSSH: config.AppsBindIPSSH,
AppsPath: config.AppsPath,
}
err := processor.SetPassword(password)
if err != nil {
log.Println("ERROR password update problem: " + err.Error())
publish(message.AppName, "backend problem", true)
return err
}
publish(message.AppName, "password updated", false)
return nil
}
// Application processes
func processesEventHandler(m *nats.Msg, message *RequestMessage) error {
processor := glue.Processor{
AppName: message.AppName,
DB: common.GetDBConnection(),
SnapshotProcessor: &snapshotProcessor,
DockerSock: config.DockerSocket,
BindIPHTTP: config.AppsBindIPHTTP,
BindIPSSH: config.AppsBindIPSSH,
AppsPath: config.AppsPath,
}
processes, err := processor.Processes()
if err != nil {
log.Println("ERROR processes list problem: " + err.Error())
publish(message.AppName, "backend problem", true)
return err
}
reply := ReplyMessage{
Payload: processes,
}
data, err := json.Marshal(reply)
if err != nil {
log.Println("ERROR processes list problem: " + err.Error())
publish(message.AppName, "backend problem", true)
return err
}
err = m.Respond(data)
if err != nil {
log.Println("ERROR processes list problem: " + err.Error())
return err
}
return nil
}
// Enable one of the supported technologies or services (python, node, redis, ...)
// If payload contains only name of the tech the default version for given image is selected.
// Otherwise it can be passed in format tech:version.
func enableTechEventHandler(m *nats.Msg, message *RequestMessage) error {
matched, err := regexp.Match(`[a-z0-9A-Z]*:?[0-9\.\-]*`, []byte(message.Payload))
if err != nil {
log.Println("ERROR enable tech problem: " + err.Error())
publish(message.AppName, "backend problem", true)
return err
}
if !matched {
return errors.New("payload malformation, it has to be in format tech:version")
}
service := message.Payload
version := ""
if strings.Contains(service, ":") {
parts := strings.SplitN(message.Payload, ":", 2)
if len(parts) != 2 {
return errors.New("service and version malformat")
}
service = parts[0]
version = parts[1]
}
processor := glue.Processor{
AppName: message.AppName,
DB: common.GetDBConnection(),
SnapshotProcessor: &snapshotProcessor,
DockerSock: config.DockerSocket,
BindIPHTTP: config.AppsBindIPHTTP,
BindIPSSH: config.AppsBindIPSSH,
AppsPath: config.AppsPath,
}
processor.EnableTech(service, version)
if err != nil {
log.Println("ERROR enable tech problem: " + err.Error())
publish(message.AppName, "backend problem", true)
return err
}
publish(message.AppName, "tech updated", false)
return nil
}
// Rebuilds existing app, it keeps the data but creates the container again
func rebuildEventHandler(m *nats.Msg, message *RequestMessage) error {
processor := glue.Processor{
AppName: message.AppName,
DB: common.GetDBConnection(),
SnapshotProcessor: &snapshotProcessor,
DockerSock: config.DockerSocket,
BindIPHTTP: config.AppsBindIPHTTP,
BindIPSSH: config.AppsBindIPSSH,
AppsPath: config.AppsPath,
}
err := processor.Rebuild()
if err != nil {
log.Println("ERROR rebuild app problem: " + err.Error())
publish(message.AppName, "backend problem", true)
return err
}
publish(message.AppName, "app rebuild", false)
return nil
}
// Adds new label
func addLabelEventHandler(m *nats.Msg, message *RequestMessage) error {
label := message.Payload
processor := glue.Processor{
AppName: message.AppName,
DB: common.GetDBConnection(),
SnapshotProcessor: &snapshotProcessor,
DockerSock: config.DockerSocket,
BindIPHTTP: config.AppsBindIPHTTP,
BindIPSSH: config.AppsBindIPSSH,
AppsPath: config.AppsPath,
}
err := processor.AddLabel(label)
if err != nil {
log.Println("ERROR add label problem: " + err.Error())
publish(message.AppName, "backend problem", true)
return err
}
publish(message.AppName, "label added", false)
return nil
}
// Removes existing label
func removeLabelEventHandler(m *nats.Msg, message *RequestMessage) error {
label := message.Payload
processor := glue.Processor{
AppName: message.AppName,
DB: common.GetDBConnection(),
SnapshotProcessor: &snapshotProcessor,
DockerSock: config.DockerSocket,
BindIPHTTP: config.AppsBindIPHTTP,
BindIPSSH: config.AppsBindIPSSH,
AppsPath: config.AppsPath,
}
err := processor.RemoveLabel(label)
if err != nil {
log.Println("ERROR remove label problem: " + err.Error())
publish(message.AppName, "backend problem", true)
return err
}
publish(message.AppName, "label removed", false)
return nil
}
// Orphans returns directories in /srv that doesn't match any hosted application
func listOrphansEventHandler(m *nats.Msg, message *RequestMessage) error {
reply := ReplyMessage{
Error: true,
Payload: "not implemented yet",
}
data, err := json.Marshal(reply)
if err != nil {
log.Println("ERROR orphans list problem: " + err.Error())
return err
}
err = m.Respond(data)
if err != nil {
log.Println("ERROR orphans list problem: " + err.Error())
return err
}
return nil
}
// Save metadata for the app
func saveMetadataEventHandler(m *nats.Msg, message *RequestMessage) error {
processor := glue.Processor{
AppName: message.AppName,
DB: common.GetDBConnection(),
SnapshotProcessor: &snapshotProcessor,
DockerSock: config.DockerSocket,
BindIPHTTP: config.AppsBindIPHTTP,
BindIPSSH: config.AppsBindIPSSH,
AppsPath: config.AppsPath,
}
err := processor.SaveMetadata(message.Payload)
if err != nil {
return fmt.Errorf("error while save metadata: %v", err.Error())
}
return nil
}
/*
getNodeEventHandler returns info about the node including performance index
*/
func getNodeEventHandler(m *nats.Msg, message *RequestMessage) error {
processor := glue.Processor{
AppName: message.AppName,
DB: common.GetDBConnection(),
SnapshotProcessor: &snapshotProcessor,
DockerSock: config.DockerSocket,
BindIPHTTP: config.AppsBindIPHTTP,
BindIPSSH: config.AppsBindIPSSH,
AppsPath: config.AppsPath,
NodeProcessor: &nodeProcessor,
}
node, err := processor.GetNode()
if err != nil {
log.Println("ERROR performance index problem: " + err.Error())
publish(message.AppName, "backend problem", true)
return err
}
reply := ReplyMessage{
Payload: node,
}
data, err := json.Marshal(reply)
if err != nil {
log.Println("ERROR performance index problem: " + err.Error())
publish(message.AppName, "backend problem", true)
return err
}
err = m.Respond(data)
if err != nil {
log.Println("ERROR performance index problem: " + err.Error())
return err
}
return nil
}
/*
createSnapshotEventHandler create snapshot of given application
# Uses appName from the message struct
Payload: no payload needed
Response: notification when it's done or error
*/
func createSnapshotEventHandler(m *nats.Msg, message *RequestMessage) error {
processor := glue.Processor{
AppName: message.AppName,
DB: common.GetDBConnection(),
SnapshotProcessor: &snapshotProcessor,
DockerSock: config.DockerSocket,
BindIPHTTP: config.AppsBindIPHTTP,
BindIPSSH: config.AppsBindIPSSH,
AppsPath: config.AppsPath,
}
err := processor.CreateSnapshot(strings.Split(message.Payload, ","))
if err != nil {
log.Println("ERROR create snapshot error: " + err.Error())
publish(message.AppName, "backend problem", true)
return err
}
publish(message.AppName, "snapshot created", false)
return nil
}
/*
restoreFromSnapshotEventHandler restores app from a snapshot. The app has to exist
before it can be restored. Any snapshot can be used to restore any application.
Use labels to store information about what app should be created.
Uses appName from the message struct as the destination app where the data should
be restored
Payload: string with the snapshot name
Response: notification when it's done or error
*/
func restoreFromSnapshotEventHandler(m *nats.Msg, message *RequestMessage) error {
processor := glue.Processor{
AppName: message.AppName,
DB: common.GetDBConnection(),
SnapshotProcessor: &snapshotProcessor,
DockerSock: config.DockerSocket,
BindIPHTTP: config.AppsBindIPHTTP,
BindIPSSH: config.AppsBindIPSSH,
AppsPath: config.AppsPath,
}
err := processor.RestoreFromSnapshot(message.Payload)
if err != nil {
log.Println("ERROR start application problem: " + err.Error())
publish(message.AppName, "backend problem", true)
return err
}
// notify clients that it's all done
publish(message.AppName, "snapshot restored", false)
return nil
}
/*
listSnapshotsEventHandler returns list of snapshots related to a single application
# Uses appName from the message
Payload: no payload needed
Response: replies with list of snapshots or an error message
*/
func listSnapshotsEventHandler(m *nats.Msg, message *RequestMessage) error {
processor := glue.Processor{
AppName: message.AppName,
DB: common.GetDBConnection(),
SnapshotProcessor: &snapshotProcessor,
DockerSock: config.DockerSocket,
BindIPHTTP: config.AppsBindIPHTTP,
BindIPSSH: config.AppsBindIPSSH,
AppsPath: config.AppsPath,
}
snapshots, err := processor.ListSnapshots()
if err != nil {
return errorReplyFormater(m, "backend error", err)
}
reply := ReplyMessage{
Payload: snapshots,
}
data, err := json.Marshal(reply)
if err != nil {
return errorReplyFormater(m, "reply formatter error", err)
}
err = m.Respond(data)
if err != nil {
log.Println("ERROR: list of snapshots:", err.Error())
}
return nil
}
/*
listAppsSnapshotsEventHandler returns list of snapshots related to list of application names.
Payload: list of appNames separated by comma (no spaces)
Response: replies with list of snapshots or an error message
*/
func listAppsSnapshotsEventHandler(m *nats.Msg, message *RequestMessage) error {
processor := glue.Processor{
AppName: message.AppName,
DB: common.GetDBConnection(),
SnapshotProcessor: &snapshotProcessor,
DockerSock: config.DockerSocket,
BindIPHTTP: config.AppsBindIPHTTP,
BindIPSSH: config.AppsBindIPSSH,
AppsPath: config.AppsPath,
}
snapshots, err := processor.ListAppsSnapshots(strings.Split(message.Payload, ","))
if err != nil {
return errorReplyFormater(m, "backend error", err)
}
reply := ReplyMessage{
Payload: snapshots,
}
data, err := json.Marshal(reply)
if err != nil {
return errorReplyFormater(m, "reply formatter error", err)
}
err = m.Respond(data)
if err != nil {
log.Println("ERROR: list of snapshots:", err.Error())
}
return nil
}
/*
listSnapshotsByLabelEventHandler returns list of snapshots with given label
Payload: snapshot label
Response: replies with list of snapshots or an error message
*/
func listSnapshotsByLabelEventHandler(m *nats.Msg, message *RequestMessage) error {
processor := glue.Processor{
AppName: message.AppName,
DB: common.GetDBConnection(),
SnapshotProcessor: &snapshotProcessor,
DockerSock: config.DockerSocket,
BindIPHTTP: config.AppsBindIPHTTP,
BindIPSSH: config.AppsBindIPSSH,
AppsPath: config.AppsPath,
}
snapshots, err := processor.ListSnapshotsByLabel(message.Payload)
if err != nil {
return errorReplyFormater(m, "backend error", err)
}
reply := ReplyMessage{
Payload: snapshots,
}
data, err := json.Marshal(reply)
if err != nil {
return errorReplyFormater(m, "reply formatter error", err)
}
err = m.Respond(data)
if err != nil {
log.Println("ERROR: list of snapshots:", err.Error())
}
return nil
}
/*
getSnapshotEventHandler returns a single snapshot for given key from the request payload.
Payload: snapshot's key
Response: snapshot metadata
*/
func getSnapshotEventHandler(m *nats.Msg, message *RequestMessage) error {
processor := glue.Processor{
AppName: message.AppName,
DB: common.GetDBConnection(),
SnapshotProcessor: &snapshotProcessor,
DockerSock: config.DockerSocket,
BindIPHTTP: config.AppsBindIPHTTP,
BindIPSSH: config.AppsBindIPSSH,
AppsPath: config.AppsPath,
}
snapshot, err := processor.GetSnapshot(message.Payload)
if err != nil {
return errorReplyFormater(m, "backend error", err)
}
data, err := json.Marshal(snapshot)
if err != nil {
return errorReplyFormater(m, "reply formatter error", err)
}
err = m.Respond(data)
if err != nil {
log.Println("ERROR: get snapshot:", err.Error())
}
return nil
}
/*
getSnapshotDownloadLinkEventHandler return URL that can be used to download snapshot
Payload: string with a snapshot name (key)
Response: string with the URL
*/
func getSnapshotDownloadLinkEventHandler(m *nats.Msg, message *RequestMessage) error {
processor := glue.Processor{
AppName: message.AppName,
DB: common.GetDBConnection(),
SnapshotProcessor: &snapshotProcessor,
DockerSock: config.DockerSocket,
BindIPHTTP: config.AppsBindIPHTTP,
BindIPSSH: config.AppsBindIPSSH,
AppsPath: config.AppsPath,
}
link, err := processor.GetSnapshotDownloadLink(message.Payload)
if err != nil {
return errorReplyFormater(m, "backend error", err)
}
reply := ReplyMessage{
Payload: link,
}
data, err := json.Marshal(reply)
if err != nil {
return errorReplyFormater(m, "reply formatter error", err)
}
err = m.Respond(data)
if err != nil {
log.Println("ERROR: get snapshot:", err.Error())
}
return nil
}
/*
deleteSnapshotEventHandler delete a single snapshot. This is not bound to application name.
Payload: string with a snapshot name
Response: notification when it's done or error
*/
func deleteSnapshotEventHandler(m *nats.Msg, message *RequestMessage) error {
processor := glue.Processor{
AppName: message.AppName,
DB: common.GetDBConnection(),
SnapshotProcessor: &snapshotProcessor,
DockerSock: config.DockerSocket,
BindIPHTTP: config.AppsBindIPHTTP,
BindIPSSH: config.AppsBindIPSSH,
AppsPath: config.AppsPath,
}
err := processor.DeleteSnapshot(message.Payload)
if err != nil {
return errorReplyFormater(m, "backend error", err)
}
publish(message.AppName, "snapshot deleted", false)
return nil
}
/*
deleteAppSnapshotsEventHandler deletes all snapshots related to a single application
# Uses appName from the message struct
Payload: no payload needed
Response: notification when it's done or error
*/
func deleteAppSnapshotsEventHandler(m *nats.Msg, message *RequestMessage) error {
processor := glue.Processor{
AppName: message.AppName,
DB: common.GetDBConnection(),
SnapshotProcessor: &snapshotProcessor,
DockerSock: config.DockerSocket,
BindIPHTTP: config.AppsBindIPHTTP,
BindIPSSH: config.AppsBindIPSSH,
AppsPath: config.AppsPath,
}
err := processor.DeleteAppSnapshots()
if err != nil {
return errorReplyFormater(m, "backend error", err)
}
publish(message.AppName, "snapshots deleted", false)
return nil
}
func getActiveTechHandler(m *nats.Msg, message *RequestMessage) error {
processor := glue.Processor{
AppName: message.AppName,
DB: common.GetDBConnection(),
SnapshotProcessor: &snapshotProcessor,
DockerSock: config.DockerSocket,
BindIPHTTP: config.AppsBindIPHTTP,
BindIPSSH: config.AppsBindIPSSH,
AppsPath: config.AppsPath,
}
tech, err := processor.GetActiveTech()
if err != nil {
log.Printf("backend error: %v\n", err)
return errorReplyFormater(m, "backend error", err)
}
// Assembling reply message
reply := ReplyMessage{
Payload: tech,
}
data, err := json.Marshal(reply)
if err != nil {
return errorReplyFormater(m, "reply formatter error", err)
}
err = m.Respond(data)
if err != nil {
log.Println("ERROR: get app:", err.Error())
return err
}
return nil
}