mirror of
https://github.com/ClusterCockpit/cc-backend
synced 2024-12-26 13:29:05 +01:00
Cleanup and restructure
This commit is contained in:
parent
4cccbb20d8
commit
ad705f1424
77
routes.go
77
routes.go
@ -2,10 +2,13 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/ClusterCockpit/cc-backend/auth"
|
"github.com/ClusterCockpit/cc-backend/auth"
|
||||||
"github.com/ClusterCockpit/cc-backend/config"
|
"github.com/ClusterCockpit/cc-backend/config"
|
||||||
|
"github.com/ClusterCockpit/cc-backend/schema"
|
||||||
"github.com/ClusterCockpit/cc-backend/templates"
|
"github.com/ClusterCockpit/cc-backend/templates"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
)
|
)
|
||||||
@ -20,10 +23,59 @@ type Route struct {
|
|||||||
Setup func(i InfoType, r *http.Request) InfoType
|
Setup func(i InfoType, r *http.Request) InfoType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func buildFilterPresets(query url.Values) map[string]interface{} {
|
||||||
|
filterPresets := map[string]interface{}{}
|
||||||
|
|
||||||
|
if query.Get("cluster") != "" {
|
||||||
|
filterPresets["cluster"] = query.Get("cluster")
|
||||||
|
}
|
||||||
|
if query.Get("partition") != "" {
|
||||||
|
filterPresets["partition"] = query.Get("partition")
|
||||||
|
}
|
||||||
|
if query.Get("project") != "" {
|
||||||
|
filterPresets["project"] = query.Get("project")
|
||||||
|
filterPresets["projectMatch"] = "eq"
|
||||||
|
}
|
||||||
|
if query.Get("state") != "" && schema.JobState(query.Get("state")).Valid() {
|
||||||
|
filterPresets["state"] = query.Get("state")
|
||||||
|
}
|
||||||
|
if rawtags, ok := query["tag"]; ok {
|
||||||
|
tags := make([]int, len(rawtags))
|
||||||
|
for i, tid := range rawtags {
|
||||||
|
var err error
|
||||||
|
tags[i], err = strconv.Atoi(tid)
|
||||||
|
if err != nil {
|
||||||
|
tags[i] = -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
filterPresets["tags"] = tags
|
||||||
|
}
|
||||||
|
if query.Get("numNodes") != "" {
|
||||||
|
parts := strings.Split(query.Get("numNodes"), "-")
|
||||||
|
if len(parts) == 2 {
|
||||||
|
a, e1 := strconv.Atoi(parts[0])
|
||||||
|
b, e2 := strconv.Atoi(parts[1])
|
||||||
|
if e1 == nil && e2 == nil {
|
||||||
|
filterPresets["numNodes"] = map[string]int{"from": a, "to": b}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if query.Get("jobId") != "" {
|
||||||
|
filterPresets["jobId"] = query.Get("jobId")
|
||||||
|
}
|
||||||
|
if query.Get("arrayJobId") != "" {
|
||||||
|
if num, err := strconv.Atoi(query.Get("arrayJobId")); err == nil {
|
||||||
|
filterPresets["arrayJobId"] = num
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return filterPresets
|
||||||
|
}
|
||||||
|
|
||||||
func setupRoutes(router *mux.Router, routes []Route) {
|
func setupRoutes(router *mux.Router, routes []Route) {
|
||||||
for _, route := range routes {
|
for _, route := range routes {
|
||||||
_route := route
|
route := route
|
||||||
router.HandleFunc(_route.Route, func(rw http.ResponseWriter, r *http.Request) {
|
router.HandleFunc(route.Route, func(rw http.ResponseWriter, r *http.Request) {
|
||||||
conf, err := config.GetUIConfig(r)
|
conf, err := config.GetUIConfig(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||||
@ -42,17 +94,22 @@ func setupRoutes(router *mux.Router, routes []Route) {
|
|||||||
infos["admin"] = false
|
infos["admin"] = false
|
||||||
}
|
}
|
||||||
|
|
||||||
infos = _route.Setup(infos, r)
|
infos = route.Setup(infos, r)
|
||||||
if id, ok := infos["id"]; ok {
|
if id, ok := infos["id"]; ok {
|
||||||
_route.Title = strings.Replace(_route.Title, "<ID>", id.(string), 1)
|
route.Title = strings.Replace(route.Title, "<ID>", id.(string), 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
templates.Render(rw, r, _route.Template, &templates.Page{
|
page := templates.Page{
|
||||||
Title: _route.Title,
|
Title: route.Title,
|
||||||
Config: conf,
|
Config: conf,
|
||||||
Infos: infos,
|
Infos: infos,
|
||||||
FilterPresets: buildFilterPresets(r.URL.Query()),
|
}
|
||||||
})
|
|
||||||
|
if route.Filter {
|
||||||
|
page.FilterPresets = buildFilterPresets(r.URL.Query())
|
||||||
|
}
|
||||||
|
|
||||||
|
templates.Render(rw, r, route.Template, &page)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
124
runtimeSetup.go
Normal file
124
runtimeSetup.go
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"os/user"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
func loadEnv(file string) error {
|
||||||
|
f, err := os.Open(file)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer f.Close()
|
||||||
|
s := bufio.NewScanner(bufio.NewReader(f))
|
||||||
|
for s.Scan() {
|
||||||
|
line := s.Text()
|
||||||
|
if strings.HasPrefix(line, "#") || len(line) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.Contains(line, "#") {
|
||||||
|
return errors.New("'#' are only supported at the start of a line")
|
||||||
|
}
|
||||||
|
|
||||||
|
line = strings.TrimPrefix(line, "export ")
|
||||||
|
parts := strings.SplitN(line, "=", 2)
|
||||||
|
if len(parts) != 2 {
|
||||||
|
return fmt.Errorf("unsupported line: %#v", line)
|
||||||
|
}
|
||||||
|
|
||||||
|
key := strings.TrimSpace(parts[0])
|
||||||
|
val := strings.TrimSpace(parts[1])
|
||||||
|
if strings.HasPrefix(val, "\"") {
|
||||||
|
if !strings.HasSuffix(val, "\"") {
|
||||||
|
return fmt.Errorf("unsupported line: %#v", line)
|
||||||
|
}
|
||||||
|
|
||||||
|
runes := []rune(val[1 : len(val)-1])
|
||||||
|
sb := strings.Builder{}
|
||||||
|
for i := 0; i < len(runes); i++ {
|
||||||
|
if runes[i] == '\\' {
|
||||||
|
i++
|
||||||
|
switch runes[i] {
|
||||||
|
case 'n':
|
||||||
|
sb.WriteRune('\n')
|
||||||
|
case 'r':
|
||||||
|
sb.WriteRune('\r')
|
||||||
|
case 't':
|
||||||
|
sb.WriteRune('\t')
|
||||||
|
case '"':
|
||||||
|
sb.WriteRune('"')
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unsupprorted escape sequence in quoted string: backslash %#v", runes[i])
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
sb.WriteRune(runes[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
val = sb.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
os.Setenv(key, val)
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
func dropPrivileges() error {
|
||||||
|
if programConfig.Group != "" {
|
||||||
|
g, err := user.LookupGroup(programConfig.Group)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
gid, _ := strconv.Atoi(g.Gid)
|
||||||
|
if err := syscall.Setgid(gid); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if programConfig.User != "" {
|
||||||
|
u, err := user.Lookup(programConfig.User)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
uid, _ := strconv.Atoi(u.Uid)
|
||||||
|
if err := syscall.Setuid(uid); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// If started via systemd, inform systemd that we are running:
|
||||||
|
// https://www.freedesktop.org/software/systemd/man/sd_notify.html
|
||||||
|
func systemdNotifiy(ready bool, status string) {
|
||||||
|
if os.Getenv("NOTIFY_SOCKET") == "" {
|
||||||
|
// Not started using systemd
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
args := []string{fmt.Sprintf("--pid=%d", os.Getpid())}
|
||||||
|
if ready {
|
||||||
|
args = append(args, "--ready")
|
||||||
|
}
|
||||||
|
|
||||||
|
if status != "" {
|
||||||
|
args = append(args, fmt.Sprintf("--status=%s", status))
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := exec.Command("systemd-notify", args...)
|
||||||
|
cmd.Run() // errors ignored on purpose, there is not much to do anyways.
|
||||||
|
}
|
313
server.go
313
server.go
@ -1,7 +1,6 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@ -11,12 +10,8 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"os/user"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
@ -31,7 +26,6 @@ import (
|
|||||||
"github.com/ClusterCockpit/cc-backend/graph/generated"
|
"github.com/ClusterCockpit/cc-backend/graph/generated"
|
||||||
"github.com/ClusterCockpit/cc-backend/log"
|
"github.com/ClusterCockpit/cc-backend/log"
|
||||||
"github.com/ClusterCockpit/cc-backend/metricdata"
|
"github.com/ClusterCockpit/cc-backend/metricdata"
|
||||||
"github.com/ClusterCockpit/cc-backend/schema"
|
|
||||||
"github.com/ClusterCockpit/cc-backend/templates"
|
"github.com/ClusterCockpit/cc-backend/templates"
|
||||||
"github.com/gorilla/handlers"
|
"github.com/gorilla/handlers"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
@ -455,310 +449,3 @@ func main() {
|
|||||||
wg.Wait()
|
wg.Wait()
|
||||||
log.Print("Gracefull shutdown completed!")
|
log.Print("Gracefull shutdown completed!")
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildFilterPresets(query url.Values) map[string]interface{} {
|
|
||||||
filterPresets := map[string]interface{}{}
|
|
||||||
|
|
||||||
if query.Get("cluster") != "" {
|
|
||||||
filterPresets["cluster"] = query.Get("cluster")
|
|
||||||
}
|
|
||||||
if query.Get("partition") != "" {
|
|
||||||
filterPresets["partition"] = query.Get("partition")
|
|
||||||
}
|
|
||||||
if query.Get("project") != "" {
|
|
||||||
filterPresets["project"] = query.Get("project")
|
|
||||||
filterPresets["projectMatch"] = "eq"
|
|
||||||
}
|
|
||||||
if query.Get("state") != "" && schema.JobState(query.Get("state")).Valid() {
|
|
||||||
filterPresets["state"] = query.Get("state")
|
|
||||||
}
|
|
||||||
if rawtags, ok := query["tag"]; ok {
|
|
||||||
tags := make([]int, len(rawtags))
|
|
||||||
for i, tid := range rawtags {
|
|
||||||
var err error
|
|
||||||
tags[i], err = strconv.Atoi(tid)
|
|
||||||
if err != nil {
|
|
||||||
tags[i] = -1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
filterPresets["tags"] = tags
|
|
||||||
}
|
|
||||||
if query.Get("numNodes") != "" {
|
|
||||||
parts := strings.Split(query.Get("numNodes"), "-")
|
|
||||||
if len(parts) == 2 {
|
|
||||||
a, e1 := strconv.Atoi(parts[0])
|
|
||||||
b, e2 := strconv.Atoi(parts[1])
|
|
||||||
if e1 == nil && e2 == nil {
|
|
||||||
filterPresets["numNodes"] = map[string]int{"from": a, "to": b}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if query.Get("jobId") != "" {
|
|
||||||
filterPresets["jobId"] = query.Get("jobId")
|
|
||||||
}
|
|
||||||
if query.Get("arrayJobId") != "" {
|
|
||||||
if num, err := strconv.Atoi(query.Get("arrayJobId")); err == nil {
|
|
||||||
filterPresets["arrayJobId"] = num
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return filterPresets
|
|
||||||
}
|
|
||||||
|
|
||||||
// func monitoringRoutes(router *mux.Router, resolver *graph.Resolver) {
|
|
||||||
|
|
||||||
// router.HandleFunc("/monitoring/jobs/", func(rw http.ResponseWriter, r *http.Request) {
|
|
||||||
// conf, infos, err := prepareRoute(r)
|
|
||||||
// if err != nil {
|
|
||||||
// http.Error(rw, err.Error(), http.StatusInternalServerError)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
|
|
||||||
// templates.Render(rw, r, "monitoring/jobs.tmpl", &templates.Page{
|
|
||||||
// Title: "Jobs - ClusterCockpit",
|
|
||||||
// Config: conf,
|
|
||||||
// Infos: infos,
|
|
||||||
// FilterPresets: buildFilterPresets(r.URL.Query()),
|
|
||||||
// })
|
|
||||||
// })
|
|
||||||
|
|
||||||
// router.HandleFunc("/monitoring/job/{id:[0-9]+}", func(rw http.ResponseWriter, r *http.Request) {
|
|
||||||
// conf, infos, err := prepareRoute(r)
|
|
||||||
// if err != nil {
|
|
||||||
// http.Error(rw, err.Error(), http.StatusInternalServerError)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
|
|
||||||
// id := mux.Vars(r)["id"]
|
|
||||||
// job, err := resolver.Query().Job(r.Context(), id)
|
|
||||||
// if err != nil {
|
|
||||||
// http.Error(rw, err.Error(), http.StatusNotFound)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
|
|
||||||
// infos["id"] = id
|
|
||||||
// infos["jobId"] = job.JobID
|
|
||||||
// infos["clusterId"] = job.Cluster
|
|
||||||
|
|
||||||
// templates.Render(rw, r, "monitoring/job.tmpl", &templates.Page{
|
|
||||||
// Title: fmt.Sprintf("Job %d - ClusterCockpit", job.JobID),
|
|
||||||
// Config: conf,
|
|
||||||
// Infos: infos,
|
|
||||||
// })
|
|
||||||
// })
|
|
||||||
|
|
||||||
// router.HandleFunc("/monitoring/users/", func(rw http.ResponseWriter, r *http.Request) {
|
|
||||||
// conf, infos, err := prepareRoute(r)
|
|
||||||
// if err != nil {
|
|
||||||
// http.Error(rw, err.Error(), http.StatusInternalServerError)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
|
|
||||||
// infos["listType"] = "USER"
|
|
||||||
|
|
||||||
// templates.Render(rw, r, "monitoring/list.tmpl", &templates.Page{
|
|
||||||
// Title: "Users - ClusterCockpit",
|
|
||||||
// Config: conf,
|
|
||||||
// FilterPresets: buildFilterPresets(r.URL.Query()),
|
|
||||||
// Infos: infos,
|
|
||||||
// })
|
|
||||||
// })
|
|
||||||
|
|
||||||
// router.HandleFunc("/monitoring/projects/", func(rw http.ResponseWriter, r *http.Request) {
|
|
||||||
// conf, infos, err := prepareRoute(r)
|
|
||||||
// if err != nil {
|
|
||||||
// http.Error(rw, err.Error(), http.StatusInternalServerError)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
|
|
||||||
// infos["listType"] = "PROJECT"
|
|
||||||
|
|
||||||
// templates.Render(rw, r, "monitoring/list.tmpl", &templates.Page{
|
|
||||||
// Title: "Projects - ClusterCockpit",
|
|
||||||
// Config: conf,
|
|
||||||
// FilterPresets: buildFilterPresets(r.URL.Query()),
|
|
||||||
// Infos: infos,
|
|
||||||
// })
|
|
||||||
// })
|
|
||||||
|
|
||||||
// router.HandleFunc("/monitoring/user/{id}", func(rw http.ResponseWriter, r *http.Request) {
|
|
||||||
// conf, infos, err := prepareRoute(r)
|
|
||||||
// if err != nil {
|
|
||||||
// http.Error(rw, err.Error(), http.StatusInternalServerError)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
|
|
||||||
// id := mux.Vars(r)["id"]
|
|
||||||
// // TODO: One could check if the user exists, but that would be unhelpfull if authentication
|
|
||||||
// // is disabled or the user does not exist but has started jobs.
|
|
||||||
// infos["username"] = id
|
|
||||||
|
|
||||||
// templates.Render(rw, r, "monitoring/user.tmpl", &templates.Page{
|
|
||||||
// Title: fmt.Sprintf("User %s - ClusterCockpit", id),
|
|
||||||
// Config: conf,
|
|
||||||
// Infos: infos,
|
|
||||||
// FilterPresets: buildFilterPresets(r.URL.Query()),
|
|
||||||
// })
|
|
||||||
// })
|
|
||||||
|
|
||||||
// router.HandleFunc("/monitoring/systems/", func(rw http.ResponseWriter, r *http.Request) {
|
|
||||||
// // TODO: List all clusters?
|
|
||||||
// http.Redirect(rw, r, "/", http.StatusTemporaryRedirect)
|
|
||||||
// })
|
|
||||||
|
|
||||||
// router.HandleFunc("/monitoring/systems/{cluster}", func(rw http.ResponseWriter, r *http.Request) {
|
|
||||||
// conf, infos, err := prepareRoute(r)
|
|
||||||
// if err != nil {
|
|
||||||
// http.Error(rw, err.Error(), http.StatusInternalServerError)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
|
|
||||||
// vars := mux.Vars(r)
|
|
||||||
// infos["cluster"] = vars["cluster"]
|
|
||||||
// from, to := r.URL.Query().Get("from"), r.URL.Query().Get("to")
|
|
||||||
// if from != "" || to != "" {
|
|
||||||
// infos["from"] = from
|
|
||||||
// infos["to"] = to
|
|
||||||
// }
|
|
||||||
|
|
||||||
// templates.Render(rw, r, "monitoring/systems.tmpl", &templates.Page{
|
|
||||||
// Title: fmt.Sprintf("Cluster %s - ClusterCockpit", vars["cluster"]),
|
|
||||||
// Config: conf,
|
|
||||||
// Infos: infos,
|
|
||||||
// })
|
|
||||||
// })
|
|
||||||
|
|
||||||
// router.HandleFunc("/monitoring/node/{cluster}/{hostname}", func(rw http.ResponseWriter, r *http.Request) {
|
|
||||||
// conf, infos, err := prepareRoute(r)
|
|
||||||
// if err != nil {
|
|
||||||
// http.Error(rw, err.Error(), http.StatusInternalServerError)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
|
|
||||||
// vars := mux.Vars(r)
|
|
||||||
// infos["cluster"] = vars["cluster"]
|
|
||||||
// infos["hostname"] = vars["hostname"]
|
|
||||||
// from, to := r.URL.Query().Get("from"), r.URL.Query().Get("to")
|
|
||||||
// if from != "" || to != "" {
|
|
||||||
// infos["from"] = from
|
|
||||||
// infos["to"] = to
|
|
||||||
// }
|
|
||||||
|
|
||||||
// templates.Render(rw, r, "monitoring/node.tmpl", &templates.Page{
|
|
||||||
// Title: fmt.Sprintf("Host %s - ClusterCockpit", vars["hostname"]),
|
|
||||||
// Config: conf,
|
|
||||||
// Infos: infos,
|
|
||||||
// })
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
|
|
||||||
func loadEnv(file string) error {
|
|
||||||
f, err := os.Open(file)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
defer f.Close()
|
|
||||||
s := bufio.NewScanner(bufio.NewReader(f))
|
|
||||||
for s.Scan() {
|
|
||||||
line := s.Text()
|
|
||||||
if strings.HasPrefix(line, "#") || len(line) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.Contains(line, "#") {
|
|
||||||
return errors.New("'#' are only supported at the start of a line")
|
|
||||||
}
|
|
||||||
|
|
||||||
line = strings.TrimPrefix(line, "export ")
|
|
||||||
parts := strings.SplitN(line, "=", 2)
|
|
||||||
if len(parts) != 2 {
|
|
||||||
return fmt.Errorf("unsupported line: %#v", line)
|
|
||||||
}
|
|
||||||
|
|
||||||
key := strings.TrimSpace(parts[0])
|
|
||||||
val := strings.TrimSpace(parts[1])
|
|
||||||
if strings.HasPrefix(val, "\"") {
|
|
||||||
if !strings.HasSuffix(val, "\"") {
|
|
||||||
return fmt.Errorf("unsupported line: %#v", line)
|
|
||||||
}
|
|
||||||
|
|
||||||
runes := []rune(val[1 : len(val)-1])
|
|
||||||
sb := strings.Builder{}
|
|
||||||
for i := 0; i < len(runes); i++ {
|
|
||||||
if runes[i] == '\\' {
|
|
||||||
i++
|
|
||||||
switch runes[i] {
|
|
||||||
case 'n':
|
|
||||||
sb.WriteRune('\n')
|
|
||||||
case 'r':
|
|
||||||
sb.WriteRune('\r')
|
|
||||||
case 't':
|
|
||||||
sb.WriteRune('\t')
|
|
||||||
case '"':
|
|
||||||
sb.WriteRune('"')
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("unsupprorted escape sequence in quoted string: backslash %#v", runes[i])
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
sb.WriteRune(runes[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
val = sb.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
os.Setenv(key, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
return s.Err()
|
|
||||||
}
|
|
||||||
|
|
||||||
func dropPrivileges() error {
|
|
||||||
if programConfig.Group != "" {
|
|
||||||
g, err := user.LookupGroup(programConfig.Group)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
gid, _ := strconv.Atoi(g.Gid)
|
|
||||||
if err := syscall.Setgid(gid); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if programConfig.User != "" {
|
|
||||||
u, err := user.Lookup(programConfig.User)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
uid, _ := strconv.Atoi(u.Uid)
|
|
||||||
if err := syscall.Setuid(uid); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// If started via systemd, inform systemd that we are running:
|
|
||||||
// https://www.freedesktop.org/software/systemd/man/sd_notify.html
|
|
||||||
func systemdNotifiy(ready bool, status string) {
|
|
||||||
if os.Getenv("NOTIFY_SOCKET") == "" {
|
|
||||||
// Not started using systemd
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
args := []string{fmt.Sprintf("--pid=%d", os.Getpid())}
|
|
||||||
if ready {
|
|
||||||
args = append(args, "--ready")
|
|
||||||
}
|
|
||||||
|
|
||||||
if status != "" {
|
|
||||||
args = append(args, fmt.Sprintf("--status=%s", status))
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd := exec.Command("systemd-notify", args...)
|
|
||||||
cmd.Run() // errors ignored on purpose, there is not much to do anyways.
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user