189 lines
3.9 KiB
Go
189 lines
3.9 KiB
Go
package main
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"regexp"
|
|
|
|
"gitea.elkins.co/Networking/kvmswitcher/internal/config"
|
|
)
|
|
|
|
const (
|
|
hostTgt = "host"
|
|
dirTo = true
|
|
dirFrom = false
|
|
)
|
|
|
|
var (
|
|
confFile = flag.String("config", "/etc/kvmswitcher/config.toml", "Path to the configuration file")
|
|
listen = flag.String("listen", ":5001", "Address and port to listen on")
|
|
curTargetId = flag.String("initial", "host", "Intitially active target")
|
|
targets config.Targets
|
|
)
|
|
|
|
func targetIds(t config.Targets) []string {
|
|
x := make([]string, len(t))
|
|
for i := range t {
|
|
x[i] = t[i].Id
|
|
}
|
|
return x
|
|
}
|
|
|
|
func main() {
|
|
log.SetOutput(os.Stderr)
|
|
flag.Parse()
|
|
|
|
c, err := config.Read(*confFile)
|
|
if err != nil {
|
|
log.Println("Could not read config file: ", err)
|
|
}
|
|
|
|
targets = c.Targets
|
|
if len(targets) == 0 {
|
|
log.Fatal("No targets configured")
|
|
}
|
|
|
|
if c.Globals.Listen != nil {
|
|
listen = c.Globals.Listen
|
|
}
|
|
|
|
log.Printf("configured targets: %v\n", targetIds(targets))
|
|
log.Printf("listening on %s\n", *listen)
|
|
http.HandleFunc("/to/", doSwitchTo)
|
|
http.HandleFunc("/from/", doSwitchFrom)
|
|
http.HandleFunc("/fromcurto/", doSwitchFromCurTo)
|
|
http.HandleFunc("/cur", doShowCur)
|
|
http.HandleFunc("/fromcur", doSwitchFromCur)
|
|
http.HandleFunc("/setcur/", doSetCur)
|
|
http.ListenAndServe(*listen, nil)
|
|
}
|
|
|
|
func getTarget(r *http.Request) (string, error) {
|
|
ct, _ := regexp.Compile("^/(from|to|fromcurto|setcur)/")
|
|
u := ct.ReplaceAllString(r.URL.String(), "")
|
|
if u == r.URL.String() {
|
|
log.Printf("Malformed request: %s\n", u)
|
|
return "", fmt.Errorf("Malformed request: %s", u)
|
|
}
|
|
return u, nil
|
|
}
|
|
|
|
func doSetCur(w http.ResponseWriter, r *http.Request) {
|
|
tgt, err := getTarget(r)
|
|
if err != nil {
|
|
w.WriteHeader(404)
|
|
fmt.Fprintf(w, "%s", err)
|
|
return
|
|
}
|
|
|
|
found := false
|
|
for i := range targets {
|
|
if targets[i].Id == tgt {
|
|
curTargetId = &targets[i].Id
|
|
found = true
|
|
}
|
|
}
|
|
if !found {
|
|
w.WriteHeader(404)
|
|
fmt.Fprintf(w, "Target %s not found", tgt)
|
|
log.Printf("setcur: target %s not configured", tgt)
|
|
}
|
|
}
|
|
|
|
func doShowCur(w http.ResponseWriter, _ *http.Request) {
|
|
fmt.Fprint(w, *curTargetId)
|
|
}
|
|
|
|
func doSwitchFromCur(w http.ResponseWriter, _ *http.Request) {
|
|
doSwitch(dirFrom, *curTargetId, w)
|
|
}
|
|
|
|
func doSwitchFrom(w http.ResponseWriter, r *http.Request) {
|
|
t, err := getTarget(r)
|
|
if err != nil {
|
|
w.WriteHeader(404)
|
|
fmt.Fprintf(w, "%s", err)
|
|
return
|
|
}
|
|
doSwitch(dirFrom, t, w)
|
|
}
|
|
|
|
func doSwitchTo(w http.ResponseWriter, r *http.Request) {
|
|
t, err := getTarget(r)
|
|
if err != nil {
|
|
w.WriteHeader(404)
|
|
fmt.Fprintf(w, "%s", err)
|
|
return
|
|
}
|
|
doSwitch(dirTo, t, w)
|
|
}
|
|
|
|
func doSwitchFromCurTo(w http.ResponseWriter, r *http.Request) {
|
|
t, err := getTarget(r)
|
|
if err != nil {
|
|
w.WriteHeader(404)
|
|
fmt.Fprintf(w, "%s", err)
|
|
return
|
|
}
|
|
doSwitch(dirFrom, *curTargetId, w)
|
|
doSwitch(dirTo, t, w)
|
|
}
|
|
|
|
func doSwitch(dir bool, tgt string, w http.ResponseWriter) {
|
|
var t *config.Target
|
|
for i := range targets {
|
|
if targets[i].Id == tgt {
|
|
t = &targets[i]
|
|
}
|
|
}
|
|
if t == nil {
|
|
fmt.Fprintf(w, "Invalid Target: %s\n", tgt)
|
|
return
|
|
}
|
|
|
|
cmds := t.CommandsFrom
|
|
toFrom := "from"
|
|
if dir == dirTo {
|
|
cmds = t.CommandsTo
|
|
toFrom = "to"
|
|
}
|
|
|
|
log.Printf("Switching %s %s\n", toFrom, tgt)
|
|
|
|
res, errs := runCommands(cmds)
|
|
// if at least one cmd worked, consider the operation successful
|
|
if len(errs) < len(cmds) {
|
|
if dir == dirTo {
|
|
curTargetId = &t.Id
|
|
} else {
|
|
h := hostTgt
|
|
curTargetId = &h
|
|
}
|
|
}
|
|
if len(errs) > 0 {
|
|
w.WriteHeader(503)
|
|
log.Printf("Switch resulted in %d errors:", len(errs))
|
|
for i, e := range errs {
|
|
log.Printf("[%d/%d]: %s", i, len(errs), e)
|
|
}
|
|
}
|
|
for _, o := range res {
|
|
fmt.Fprint(w, o)
|
|
}
|
|
}
|
|
|
|
func runCommands(cmds []config.Command) (res []string, errs []error) {
|
|
for _, c := range cmds {
|
|
o, err := c.Exec()
|
|
if err != nil {
|
|
errs = append(errs, err)
|
|
log.Printf("Error on command execution (cmd = %s): %s\n", c, err)
|
|
}
|
|
res = append(res, string(o))
|
|
}
|
|
return
|
|
}
|