-
Notifications
You must be signed in to change notification settings - Fork 0
/
control.go
107 lines (90 loc) · 3.01 KB
/
control.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
package main
import (
"context"
"encoding/json"
"errors"
"fmt"
"log/slog"
"net/http"
"strconv"
systemd "github.com/coreos/go-systemd/v22/dbus"
dbus "github.com/godbus/dbus/v5"
)
const MAX_UINT64 uint64 = ^uint64(0)
// properties that can be modified at runtime,
// see
var (
CPUAccounting = "CPUAccounting"
CPUQuotaPerSecUSec = "CPUQuotaPerSecUSec"
MemoryAccounting = "MemoryAccounting"
MemoryHigh = "MemoryHigh"
MemoryMax = "MemoryMax"
MemoryLow = "MemoryLow"
MemoryMin = "MemoryMin"
)
type controlProperty struct {
Name string `json:"name"`
Value string `json:"value"`
}
type controlRequest struct {
Unit string `json:"unit"`
Property controlProperty `json:"property"`
Runtime bool `json:"runtime"`
}
type controlResponse struct {
Unit string `json:"unit"`
Property controlProperty `json:"property"`
}
var ControlHandler = http.HandlerFunc(controlHandler)
func controlHandler(w http.ResponseWriter, r *http.Request) {
var request controlRequest
err := json.NewDecoder(r.Body).Decode(&request)
if err != nil {
slog.Warn("unable to decode json request", "err", err.Error())
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
property, err := transform(request.Property)
if err != nil {
slog.Warn("unable to create systemd property", "err", err.Error())
http.Error(w, err.Error(), http.StatusBadRequest)
}
ctx := context.Background()
conn, err := systemd.NewSystemConnectionContext(ctx)
if err != nil {
slog.Warn("unable to connect to systemd", "err", err.Error())
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
defer conn.Close()
err = conn.SetUnitPropertiesContext(ctx, request.Unit, request.Runtime, property)
if err != nil {
slog.Warn("unable to set property", "err", err.Error(), "property", property, "unit", request.Unit)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.Header().Set("X-Content-Type-Options", "nosniff")
response := controlResponse{Unit: request.Unit, Property: request.Property}
err = json.NewEncoder(w).Encode(response)
if err != nil {
slog.Error("unable to send encode response", "error", err.Error())
}
}
func transform(controlProp controlProperty) (systemd.Property, error) {
switch controlProp.Name {
case CPUAccounting, MemoryAccounting:
val, err := strconv.ParseBool(controlProp.Value)
return systemd.Property{Name: controlProp.Name, Value: dbus.MakeVariant(val)}, err
case CPUQuotaPerSecUSec, MemoryMax, MemoryHigh, MemoryMin, MemoryLow:
var val uint64
if controlProp.Value == "-1" {
return systemd.Property{Name: controlProp.Name, Value: dbus.MakeVariant(MAX_UINT64)}, nil
}
val, err := strconv.ParseUint(controlProp.Value, 10, 64)
return systemd.Property{Name: controlProp.Name, Value: dbus.MakeVariant(val)}, err
default:
msg := fmt.Sprintf("property not supported: %v", controlProp.Name)
return systemd.Property{}, errors.New(msg)
}
}