feat(network): VLAN/bridge/bond interface provisioner + IP-address apply
Fügt zwei neue systemd-oneshot-Services hinzu: - edgeguard-interfaces.service: erstellt VLAN/bridge/bond-Interfaces (ip link add/del) wenn der Operator sie über die GUI anlegt/entfernt. Ethernet + WireGuard bleiben OS-managed. - edgeguard-ipaddresses.service: bindet/entfernt IP-Adressen (ip addr add/del) nach jeder GUI-Mutation; läuft jetzt After=edgeguard-interfaces damit Interfaces immer vor den Adressen existieren. Beide Services triggern per applyAsync() in den zugehörigen Handlern (networks.go → Interfaces, ipaddresses.go → Adressen). Diff-Ansatz über *-applied.conf verhindert dass manuell gebundene Adressen/ Interfaces angefasst werden. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"log/slog"
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
@@ -13,13 +15,27 @@ import (
|
||||
)
|
||||
|
||||
type IPAddressesHandler struct {
|
||||
Repo *ipaddresses.Repo
|
||||
Audit *audit.Repo
|
||||
NodeID string
|
||||
Repo *ipaddresses.Repo
|
||||
Generator *ipaddresses.Generator
|
||||
Audit *audit.Repo
|
||||
NodeID string
|
||||
}
|
||||
|
||||
func NewIPAddressesHandler(repo *ipaddresses.Repo, a *audit.Repo, nodeID string) *IPAddressesHandler {
|
||||
return &IPAddressesHandler{Repo: repo, Audit: a, NodeID: nodeID}
|
||||
return &IPAddressesHandler{
|
||||
Repo: repo,
|
||||
Generator: ipaddresses.NewGenerator(repo),
|
||||
Audit: a,
|
||||
NodeID: nodeID,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *IPAddressesHandler) applyAsync(ctx context.Context) {
|
||||
go func() {
|
||||
if err := h.Generator.Render(ctx); err != nil {
|
||||
slog.Warn("ip-addresses: apply failed", "error", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (h *IPAddressesHandler) Register(rg *gin.RouterGroup) {
|
||||
@@ -70,6 +86,7 @@ func (h *IPAddressesHandler) Create(c *gin.Context) {
|
||||
}
|
||||
_ = h.Audit.Log(c.Request.Context(), actorOf(c), "ip_address.create",
|
||||
req.Address, out, h.NodeID)
|
||||
h.applyAsync(c.Request.Context())
|
||||
response.Created(c, out)
|
||||
}
|
||||
|
||||
@@ -94,6 +111,7 @@ func (h *IPAddressesHandler) Update(c *gin.Context) {
|
||||
}
|
||||
_ = h.Audit.Log(c.Request.Context(), actorOf(c), "ip_address.update",
|
||||
out.Address, out, h.NodeID)
|
||||
h.applyAsync(c.Request.Context())
|
||||
response.OK(c, out)
|
||||
}
|
||||
|
||||
@@ -112,5 +130,6 @@ func (h *IPAddressesHandler) Delete(c *gin.Context) {
|
||||
}
|
||||
_ = h.Audit.Log(c.Request.Context(), actorOf(c), "ip_address.delete",
|
||||
strconv.FormatInt(id, 10), gin.H{"id": id}, h.NodeID)
|
||||
h.applyAsync(c.Request.Context())
|
||||
response.NoContent(c)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"log/slog"
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
@@ -15,18 +17,34 @@ import (
|
||||
)
|
||||
|
||||
type NetworksHandler struct {
|
||||
Repo *networkifs.Repo
|
||||
IPs *ipaddresses.Repo
|
||||
Zones *firewall.ZonesRepo
|
||||
Audit *audit.Repo
|
||||
NodeID string
|
||||
Repo *networkifs.Repo
|
||||
Generator *networkifs.Generator
|
||||
IPs *ipaddresses.Repo
|
||||
Zones *firewall.ZonesRepo
|
||||
Audit *audit.Repo
|
||||
NodeID string
|
||||
}
|
||||
|
||||
func NewNetworksHandler(
|
||||
repo *networkifs.Repo, ips *ipaddresses.Repo,
|
||||
zones *firewall.ZonesRepo, a *audit.Repo, nodeID string,
|
||||
) *NetworksHandler {
|
||||
return &NetworksHandler{Repo: repo, IPs: ips, Zones: zones, Audit: a, NodeID: nodeID}
|
||||
return &NetworksHandler{
|
||||
Repo: repo,
|
||||
Generator: networkifs.NewGenerator(repo),
|
||||
IPs: ips,
|
||||
Zones: zones,
|
||||
Audit: a,
|
||||
NodeID: nodeID,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *NetworksHandler) applyAsync(ctx context.Context) {
|
||||
go func() {
|
||||
if err := h.Generator.Render(ctx); err != nil {
|
||||
slog.Warn("network-interfaces: apply failed", "error", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (h *NetworksHandler) Register(rg *gin.RouterGroup) {
|
||||
@@ -88,6 +106,7 @@ func (h *NetworksHandler) Create(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
_ = h.Audit.Log(c.Request.Context(), actorOf(c), "network_interface.create", req.Name, out, h.NodeID)
|
||||
h.applyAsync(c.Request.Context())
|
||||
response.Created(c, out)
|
||||
}
|
||||
|
||||
@@ -122,6 +141,7 @@ func (h *NetworksHandler) Update(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
_ = h.Audit.Log(c.Request.Context(), actorOf(c), "network_interface.update", out.Name, out, h.NodeID)
|
||||
h.applyAsync(c.Request.Context())
|
||||
response.OK(c, out)
|
||||
}
|
||||
|
||||
@@ -140,6 +160,7 @@ func (h *NetworksHandler) Delete(c *gin.Context) {
|
||||
}
|
||||
_ = h.Audit.Log(c.Request.Context(), actorOf(c), "network_interface.delete",
|
||||
strconv.FormatInt(id, 10), gin.H{"id": id}, h.NodeID)
|
||||
h.applyAsync(c.Request.Context())
|
||||
response.NoContent(c)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user