d9d192757b
Storage + CRUD (migration 0007, model, id-keyed store, REST handlers) + compiler rendering, each owned by a device. proxy_arp/proxy_ndp share the ProxyEntry shape via table-parameterized store helpers.
235 lines
6.4 KiB
Go
235 lines
6.4 KiB
Go
package server
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
|
|
"github.com/go-chi/chi/v5"
|
|
|
|
"git.unkin.net/unkin/tomswallapi/internal/model"
|
|
)
|
|
|
|
// mountPerDeviceL2 wires the per-device L2/misc sections: tunnels, stopped_rules,
|
|
// proxy_arp, proxy_ndp, arp_rules, maclist.
|
|
func (s *Server) mountPerDeviceL2(r chi.Router) {
|
|
idCRUD(r, "/tunnels", s.listTunnels, s.createTunnel, s.getTunnel, s.deleteTunnel)
|
|
idCRUD(r, "/stopped-rules", s.listStoppedRules, s.createStoppedRule, s.getStoppedRule, s.deleteStoppedRule)
|
|
idCRUD(r, "/proxy-arp", s.listProxyARP, s.createProxyARP, s.getProxyARP, s.deleteProxyARP)
|
|
idCRUD(r, "/proxy-ndp", s.listProxyNDP, s.createProxyNDP, s.getProxyNDP, s.deleteProxyNDP)
|
|
idCRUD(r, "/arp-rules", s.listArpRules, s.createArpRule, s.getArpRule, s.deleteArpRule)
|
|
idCRUD(r, "/maclist", s.listMaclist, s.createMaclist, s.getMaclist, s.deleteMaclist)
|
|
}
|
|
|
|
// idCRUD wires the four standard id-keyed handlers for a collection.
|
|
func idCRUD(r chi.Router, path string, list, create, get, del http.HandlerFunc) {
|
|
r.Route(path, func(r chi.Router) {
|
|
r.Get("/", list)
|
|
r.Post("/", create)
|
|
r.Get("/{id}", get)
|
|
r.Delete("/{id}", del)
|
|
})
|
|
}
|
|
|
|
func (s *Server) listTunnels(w http.ResponseWriter, r *http.Request) {
|
|
list, err := s.store.ListTunnels(r.Context())
|
|
respondList(w, list, err)
|
|
}
|
|
func (s *Server) createTunnel(w http.ResponseWriter, r *http.Request) {
|
|
var v model.Tunnel
|
|
if !decode(w, r, &v) {
|
|
return
|
|
}
|
|
if v.Device == "" || v.Type == "" || v.Zone == "" {
|
|
writeError(w, http.StatusBadRequest, "device, type, and zone are required")
|
|
return
|
|
}
|
|
id, err := s.store.CreateTunnel(r.Context(), v)
|
|
if err == nil {
|
|
v.ID = id
|
|
}
|
|
respondCreated(w, v, err)
|
|
}
|
|
func (s *Server) getTunnel(w http.ResponseWriter, r *http.Request) {
|
|
id, ok := idParam(w, r)
|
|
if !ok {
|
|
return
|
|
}
|
|
v, err := s.store.GetTunnel(r.Context(), id)
|
|
respondOne(w, v, err)
|
|
}
|
|
func (s *Server) deleteTunnel(w http.ResponseWriter, r *http.Request) {
|
|
id, ok := idParam(w, r)
|
|
if !ok {
|
|
return
|
|
}
|
|
respondDelete(w, s.store.DeleteTunnel(r.Context(), id))
|
|
}
|
|
|
|
func (s *Server) listStoppedRules(w http.ResponseWriter, r *http.Request) {
|
|
list, err := s.store.ListStoppedRules(r.Context())
|
|
respondList(w, list, err)
|
|
}
|
|
func (s *Server) createStoppedRule(w http.ResponseWriter, r *http.Request) {
|
|
var v model.StoppedRule
|
|
if !decode(w, r, &v) {
|
|
return
|
|
}
|
|
if v.Device == "" || v.Action == "" {
|
|
writeError(w, http.StatusBadRequest, "device and action are required")
|
|
return
|
|
}
|
|
id, err := s.store.CreateStoppedRule(r.Context(), v)
|
|
if err == nil {
|
|
v.ID = id
|
|
}
|
|
respondCreated(w, v, err)
|
|
}
|
|
func (s *Server) getStoppedRule(w http.ResponseWriter, r *http.Request) {
|
|
id, ok := idParam(w, r)
|
|
if !ok {
|
|
return
|
|
}
|
|
v, err := s.store.GetStoppedRule(r.Context(), id)
|
|
respondOne(w, v, err)
|
|
}
|
|
func (s *Server) deleteStoppedRule(w http.ResponseWriter, r *http.Request) {
|
|
id, ok := idParam(w, r)
|
|
if !ok {
|
|
return
|
|
}
|
|
respondDelete(w, s.store.DeleteStoppedRule(r.Context(), id))
|
|
}
|
|
|
|
func (s *Server) listProxyARP(w http.ResponseWriter, r *http.Request) {
|
|
list, err := s.store.ListProxyARP(r.Context())
|
|
respondList(w, list, err)
|
|
}
|
|
func (s *Server) createProxyARP(w http.ResponseWriter, r *http.Request) {
|
|
s.createProxy(w, r, s.store.CreateProxyARP)
|
|
}
|
|
func (s *Server) getProxyARP(w http.ResponseWriter, r *http.Request) {
|
|
id, ok := idParam(w, r)
|
|
if !ok {
|
|
return
|
|
}
|
|
v, err := s.store.GetProxyARP(r.Context(), id)
|
|
respondOne(w, v, err)
|
|
}
|
|
func (s *Server) deleteProxyARP(w http.ResponseWriter, r *http.Request) {
|
|
id, ok := idParam(w, r)
|
|
if !ok {
|
|
return
|
|
}
|
|
respondDelete(w, s.store.DeleteProxyARP(r.Context(), id))
|
|
}
|
|
|
|
func (s *Server) listProxyNDP(w http.ResponseWriter, r *http.Request) {
|
|
list, err := s.store.ListProxyNDP(r.Context())
|
|
respondList(w, list, err)
|
|
}
|
|
func (s *Server) createProxyNDP(w http.ResponseWriter, r *http.Request) {
|
|
s.createProxy(w, r, s.store.CreateProxyNDP)
|
|
}
|
|
func (s *Server) getProxyNDP(w http.ResponseWriter, r *http.Request) {
|
|
id, ok := idParam(w, r)
|
|
if !ok {
|
|
return
|
|
}
|
|
v, err := s.store.GetProxyNDP(r.Context(), id)
|
|
respondOne(w, v, err)
|
|
}
|
|
func (s *Server) deleteProxyNDP(w http.ResponseWriter, r *http.Request) {
|
|
id, ok := idParam(w, r)
|
|
if !ok {
|
|
return
|
|
}
|
|
respondDelete(w, s.store.DeleteProxyNDP(r.Context(), id))
|
|
}
|
|
|
|
// createProxy is shared by proxy_arp/ndp (identical shape).
|
|
func (s *Server) createProxy(w http.ResponseWriter, r *http.Request, create func(context.Context, model.ProxyEntry) (int64, error)) {
|
|
var v model.ProxyEntry
|
|
if !decode(w, r, &v) {
|
|
return
|
|
}
|
|
if v.Device == "" || v.Address == "" || v.External == "" {
|
|
writeError(w, http.StatusBadRequest, "device, address, and external are required")
|
|
return
|
|
}
|
|
id, err := create(r.Context(), v)
|
|
if err == nil {
|
|
v.ID = id
|
|
}
|
|
respondCreated(w, v, err)
|
|
}
|
|
|
|
func (s *Server) listArpRules(w http.ResponseWriter, r *http.Request) {
|
|
list, err := s.store.ListArpRules(r.Context())
|
|
respondList(w, list, err)
|
|
}
|
|
func (s *Server) createArpRule(w http.ResponseWriter, r *http.Request) {
|
|
var v model.ArpRule
|
|
if !decode(w, r, &v) {
|
|
return
|
|
}
|
|
if v.Device == "" || v.Action == "" {
|
|
writeError(w, http.StatusBadRequest, "device and action are required")
|
|
return
|
|
}
|
|
id, err := s.store.CreateArpRule(r.Context(), v)
|
|
if err == nil {
|
|
v.ID = id
|
|
}
|
|
respondCreated(w, v, err)
|
|
}
|
|
func (s *Server) getArpRule(w http.ResponseWriter, r *http.Request) {
|
|
id, ok := idParam(w, r)
|
|
if !ok {
|
|
return
|
|
}
|
|
v, err := s.store.GetArpRule(r.Context(), id)
|
|
respondOne(w, v, err)
|
|
}
|
|
func (s *Server) deleteArpRule(w http.ResponseWriter, r *http.Request) {
|
|
id, ok := idParam(w, r)
|
|
if !ok {
|
|
return
|
|
}
|
|
respondDelete(w, s.store.DeleteArpRule(r.Context(), id))
|
|
}
|
|
|
|
func (s *Server) listMaclist(w http.ResponseWriter, r *http.Request) {
|
|
list, err := s.store.ListMaclist(r.Context())
|
|
respondList(w, list, err)
|
|
}
|
|
func (s *Server) createMaclist(w http.ResponseWriter, r *http.Request) {
|
|
var v model.MaclistEntry
|
|
if !decode(w, r, &v) {
|
|
return
|
|
}
|
|
if v.Device == "" || v.Action == "" || v.Interface == "" {
|
|
writeError(w, http.StatusBadRequest, "device, action, and interface are required")
|
|
return
|
|
}
|
|
id, err := s.store.CreateMaclist(r.Context(), v)
|
|
if err == nil {
|
|
v.ID = id
|
|
}
|
|
respondCreated(w, v, err)
|
|
}
|
|
func (s *Server) getMaclist(w http.ResponseWriter, r *http.Request) {
|
|
id, ok := idParam(w, r)
|
|
if !ok {
|
|
return
|
|
}
|
|
v, err := s.store.GetMaclist(r.Context(), id)
|
|
respondOne(w, v, err)
|
|
}
|
|
func (s *Server) deleteMaclist(w http.ResponseWriter, r *http.Request) {
|
|
id, ok := idParam(w, r)
|
|
if !ok {
|
|
return
|
|
}
|
|
respondDelete(w, s.store.DeleteMaclist(r.Context(), id))
|
|
}
|