fea:support add/del/save network (#55)

* fea:support add/del/save network
This commit is contained in:
buliangjun
2024-04-08 22:48:23 +08:00
committed by GitHub
parent 0939850a6d
commit dfee4c956a
9 changed files with 273 additions and 79 deletions

View File

@@ -29,7 +29,7 @@ func (u Config) List(c *cli.Context) error {
name := c.String("network") name := c.String("network")
format := c.String("format") format := c.String("format")
if format == "yaml" { if format == "yaml" {
cfg.Format() cfg.FormatNetwork()
} }
if len(name) > 0 { if len(name) > 0 {
obj := cfg.GetNetwork(name) obj := cfg.GetNetwork(name)

View File

@@ -2,6 +2,7 @@ package v5
import ( import (
"github.com/luscis/openlan/cmd/api" "github.com/luscis/openlan/cmd/api"
"github.com/luscis/openlan/pkg/libol"
"github.com/luscis/openlan/pkg/schema" "github.com/luscis/openlan/pkg/schema"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
) )
@@ -11,7 +12,12 @@ type Network struct {
} }
func (u Network) Url(prefix, name string) string { func (u Network) Url(prefix, name string) string {
if name == "" {
return prefix + "/api/network" return prefix + "/api/network"
} else {
return prefix + "/api/network/" + name
}
} }
func (u Network) List(c *cli.Context) error { func (u Network) List(c *cli.Context) error {
@@ -25,6 +31,46 @@ func (u Network) List(c *cli.Context) error {
} }
} }
func (u Network) Add(c *cli.Context) error {
file := c.String("file")
network := &schema.Network{
File: file,
}
url := u.Url(c.String("url"), "")
clt := u.NewHttp(c.String("token"))
if err := clt.PostJSON(url, network, nil); err != nil {
return err
}
return nil
}
func (u Network) Remove(c *cli.Context) error {
network := c.String("name")
if len(network) == 0 {
return libol.NewErr("invalid network")
}
url := u.Url(c.String("url"), network)
clt := u.NewHttp(c.String("token"))
if err := clt.DeleteJSON(url, nil, nil); err != nil {
return err
}
return nil
}
func (u Network) Save(c *cli.Context) error {
name := c.String("name")
network := &schema.Network{
Name: name,
}
url := u.Url(c.String("url"), "")
clt := u.NewHttp(c.String("token"))
if err := clt.PutJSON(url, network, nil); err != nil {
return err
}
return nil
}
func (u Network) Commands(app *api.App) { func (u Network) Commands(app *api.App) {
openvpn := OpenVpn{} openvpn := OpenVpn{}
app.Command(&cli.Command{ app.Command(&cli.Command{
@@ -38,6 +84,32 @@ func (u Network) Commands(app *api.App) {
Aliases: []string{"ls"}, Aliases: []string{"ls"},
Action: u.List, Action: u.List,
}, },
{
Name: "add",
Usage: "Add a network",
Flags: []cli.Flag{
&cli.StringFlag{Name: "file"},
},
Action: u.Add,
},
{
Name: "remove",
Usage: "Remove the network",
Aliases: []string{"rm"},
Flags: []cli.Flag{
&cli.StringFlag{Name: "name"},
},
Action: u.Remove,
},
{
Name: "save",
Usage: "Save the network",
Aliases: []string{"sa"},
Flags: []cli.Flag{
&cli.StringFlag{Name: "name", Value: ""},
},
Action: u.Save,
},
openvpn.Commands(), openvpn.Commands(),
}, },
}) })

View File

@@ -17,6 +17,9 @@ type Switcher interface {
Server() libol.SocketServer Server() libol.SocketServer
Reload() Reload()
Save() Save()
AddNetwork(network string)
DelNetwork(network string)
SaveNetwork(network string)
} }
func NewWorkerSchema(s Switcher) schema.Worker { func NewWorkerSchema(s Switcher) schema.Worker {

View File

@@ -6,16 +6,21 @@ import (
"github.com/gorilla/mux" "github.com/gorilla/mux"
"github.com/luscis/openlan/pkg/cache" "github.com/luscis/openlan/pkg/cache"
"github.com/luscis/openlan/pkg/libol"
"github.com/luscis/openlan/pkg/models" "github.com/luscis/openlan/pkg/models"
"github.com/luscis/openlan/pkg/schema" "github.com/luscis/openlan/pkg/schema"
) )
type Network struct { type Network struct {
Switcher Switcher
} }
func (h Network) Router(router *mux.Router) { func (h Network) Router(router *mux.Router) {
router.HandleFunc("/api/network", h.List).Methods("GET") router.HandleFunc("/api/network", h.List).Methods("GET")
router.HandleFunc("/api/network", h.Post).Methods("POST")
router.HandleFunc("/api/network", h.Save).Methods("PUT")
router.HandleFunc("/api/network/{id}", h.Get).Methods("GET") router.HandleFunc("/api/network/{id}", h.Get).Methods("GET")
router.HandleFunc("/api/network/{id}", h.Delete).Methods("DELETE")
router.HandleFunc("/get/network/{id}/ovpn", h.Profile).Methods("GET") router.HandleFunc("/get/network/{id}/ovpn", h.Profile).Methods("GET")
router.HandleFunc("/api/network/{id}/openvpn/restart", h.RestartVPN).Methods("POST") router.HandleFunc("/api/network/{id}/openvpn/restart", h.RestartVPN).Methods("POST")
} }
@@ -41,6 +46,50 @@ func (h Network) Get(w http.ResponseWriter, r *http.Request) {
} }
} }
func (h Network) Post(w http.ResponseWriter, r *http.Request) {
network := &schema.Network{}
if err := GetData(r, network); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
cs := h.Switcher.Config()
file := cs.Dir("network", network.File)
if err := libol.FileExist(file); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
cs.AddNetwork(file)
if obj := cs.GetNetworkWithFile(file); obj != nil {
h.Switcher.AddNetwork(obj.Name)
} else {
http.Error(w, "Network not found", http.StatusBadRequest)
return
}
ResponseJson(w, "success")
}
func (h Network) Delete(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
network := vars["id"]
worker := GetWorker(network)
if worker == nil {
http.Error(w, "network not found", http.StatusBadRequest)
return
}
h.Switcher.DelNetwork(network)
ResponseJson(w, "success")
}
func (h Network) Save(w http.ResponseWriter, r *http.Request) {
network := &schema.Network{}
if err := GetData(r, network); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
h.Switcher.SaveNetwork(network.Name)
ResponseJson(w, "success")
}
func (h Network) Profile(w http.ResponseWriter, r *http.Request) { func (h Network) Profile(w http.ResponseWriter, r *http.Request) {
server := strings.SplitN(r.Host, ":", 2)[0] server := strings.SplitN(r.Host, ":", 2)[0]
vars := mux.Vars(r) vars := mux.Vars(r)

View File

@@ -46,7 +46,7 @@ func (h Output) Post(w http.ResponseWriter, r *http.Request) {
return return
} }
cs := h.Switcher.Config() cs := h.Switcher.Config()
if cs.Network == nil { if cs.Network[name] == nil {
http.Error(w, "network is nil", http.StatusBadRequest) http.Error(w, "network is nil", http.StatusBadRequest)
return return
} }
@@ -69,7 +69,7 @@ func (h Output) Delete(w http.ResponseWriter, r *http.Request) {
return return
} }
cs := h.Switcher.Config() cs := h.Switcher.Config()
if cs.Network == nil { if cs.Network[name] == nil {
http.Error(w, "network is nil", http.StatusBadRequest) http.Error(w, "network is nil", http.StatusBadRequest)
return return
} }

View File

@@ -7,7 +7,7 @@ func Add(router *mux.Router, switcher Switcher) {
User{}.Router(router) User{}.Router(router)
Neighbor{}.Router(router) Neighbor{}.Router(router)
Point{}.Router(router) Point{}.Router(router)
Network{}.Router(router) Network{Switcher: switcher}.Router(router)
OnLine{}.Router(router) OnLine{}.Router(router)
Lease{}.Router(router) Lease{}.Router(router)
Server{Switcher: switcher}.Router(router) Server{Switcher: switcher}.Router(router)

View File

@@ -60,7 +60,7 @@ type Switch struct {
Log Log `json:"log"` Log Log `json:"log"`
Cert *Cert `json:"cert,omitempty"` Cert *Cert `json:"cert,omitempty"`
Crypt *Crypt `json:"crypt,omitempty"` Crypt *Crypt `json:"crypt,omitempty"`
Network []*Network `json:"network,omitempty"` Network map[string]*Network `json:"network,omitempty"`
Acl map[string]*ACL `json:"acl,omitempty"` Acl map[string]*ACL `json:"acl,omitempty"`
Qos map[string]*Qos `json:"qos,omitempty"` Qos map[string]*Qos `json:"qos,omitempty"`
FireWall []FlowRule `json:"firewall,omitempty"` FireWall []FlowRule `json:"firewall,omitempty"`
@@ -77,6 +77,7 @@ func NewSwitch() *Switch {
s := &Switch{ s := &Switch{
Acl: make(map[string]*ACL, 32), Acl: make(map[string]*ACL, 32),
Qos: make(map[string]*Qos, 1024), Qos: make(map[string]*Qos, 1024),
Network: make(map[string]*Network, 32),
} }
s.Parse() s.Parse()
s.Initialize() s.Initialize()
@@ -155,43 +156,42 @@ func (s *Switch) Dir(elem ...string) string {
return filepath.Join(args...) return filepath.Join(args...)
} }
func (s *Switch) Format() { func (s *Switch) formatNetworkWithObj(obj *Network) {
for _, obj := range s.Network {
context := obj.Specifies context := obj.Specifies
obj.NewSpecifies() obj.NewSpecifies()
if obj.Specifies == nil { if obj.Specifies == nil {
continue return
} }
if data, err := libol.Marshal(context, true); err != nil { if data, err := libol.Marshal(context, true); err != nil {
libol.Warn("Switch.Format %s", err) libol.Warn("Switch.Format %s", err)
} else if err := libol.Unmarshal(obj.Specifies, data); err != nil { } else if err := libol.Unmarshal(obj.Specifies, data); err != nil {
libol.Warn("Switch.Format %s", err) libol.Warn("Switch.Format %s", err)
} }
}
func (s *Switch) FormatNetwork() {
for _, obj := range s.Network {
s.formatNetworkWithObj(obj)
} }
} }
func (s *Switch) LoadNetwork() { func (s *Switch) LoadNetworkWithFile(file string) {
files, err := filepath.Glob(s.Dir("network", "*.json"))
if err != nil {
libol.Error("Switch.LoadNetwork %s", err)
}
for _, k := range files {
obj := &Network{ obj := &Network{
Alias: s.Alias, Alias: s.Alias,
File: k, File: file,
ConfDir: s.ConfDir, ConfDir: s.ConfDir,
} }
if err := libol.UnmarshalLoad(obj, k); err != nil { if err := libol.UnmarshalLoad(obj, file); err != nil {
libol.Error("Switch.LoadNetwork %s", err) libol.Error("Switch.LoadNetwork %s", err)
continue return
} }
obj.LoadLink() obj.LoadLink()
obj.LoadRoute() obj.LoadRoute()
obj.LoadOutput() obj.LoadOutput()
s.Network = append(s.Network, obj) s.Network[obj.Name] = obj
} }
s.Format()
for _, obj := range s.Network { func (s *Switch) correctNetworkWithObj(obj *Network) {
for _, link := range obj.Links { for _, link := range obj.Links {
link.Correct() link.Correct()
} }
@@ -214,9 +214,33 @@ func (s *Switch) LoadNetwork() {
obj.Correct(s) obj.Correct(s)
s.Qos[obj.Name] = obj s.Qos[obj.Name] = obj
} }
}
func (s *Switch) CorrectNetwork() {
for _, obj := range s.Network {
s.correctNetworkWithObj(obj)
} }
} }
func (s *Switch) AddNetwork(file string) {
s.LoadNetworkWithFile(file)
net := s.GetNetworkWithFile(file)
s.formatNetworkWithObj(net)
s.correctNetworkWithObj(net)
}
func (s *Switch) LoadNetwork() {
files, err := filepath.Glob(s.Dir("network", "*.json"))
if err != nil {
libol.Error("Switch.LoadNetwork %s", err)
}
for _, k := range files {
s.LoadNetworkWithFile(k)
}
s.FormatNetwork()
s.CorrectNetwork()
}
func (s *Switch) LoadQos() { func (s *Switch) LoadQos() {
files, err := filepath.Glob(s.Dir("qos", "*.json")) files, err := filepath.Glob(s.Dir("qos", "*.json"))
if err != nil { if err != nil {
@@ -304,8 +328,12 @@ func (s *Switch) Reload() {
} }
func (s *Switch) GetNetwork(name string) *Network { func (s *Switch) GetNetwork(name string) *Network {
return s.Network[name]
}
func (s *Switch) GetNetworkWithFile(file string) *Network {
for _, obj := range s.Network { for _, obj := range s.Network {
if obj.Name == name { if obj.File == file {
return obj return obj
} }
} }

View File

@@ -24,6 +24,7 @@ type Subnet struct {
} }
type Network struct { type Network struct {
File string `json:"file,omitempty"`
Name string `json:"name"` Name string `json:"name"`
Subnet Subnet `json:"subnet"` Subnet Subnet `json:"subnet"`
Routes []PrefixRoute `json:"routes"` Routes []PrefixRoute `json:"routes"`

View File

@@ -2,6 +2,7 @@ package cswitch
import ( import (
"encoding/json" "encoding/json"
"os"
"os/exec" "os/exec"
"strconv" "strconv"
"strings" "strings"
@@ -140,6 +141,46 @@ func (v *Switch) enablePort(protocol, port string) {
}) })
} }
func (v *Switch) AddNetwork(network string) {
for _, nCfg := range v.cfg.Network {
name := nCfg.Name
if name == network {
w := NewNetworker(nCfg)
v.worker[name] = w
if w.Provider() != "vxlan" {
w.Initialize()
w.Start(v)
}
}
}
}
func (v *Switch) DelNetwork(network string) {
worker := v.worker[network]
file := worker.Config().File
if worker.Provider() != "vxlan" {
worker.Stop()
}
cache.Network.Del(network)
delete(v.worker, network)
delete(v.cfg.Network, network)
if err := os.Remove(file); err != nil {
v.out.Error("Error removing file: %s, err: %s", file, err)
}
}
func (v *Switch) SaveNetwork(network string) {
if network == "" {
for _, obj := range v.cfg.Network {
obj.Save()
}
} else {
if obj := v.cfg.GetNetwork(network); obj != nil {
obj.Save()
}
}
}
func (v *Switch) preNetwork() { func (v *Switch) preNetwork() {
for _, nCfg := range v.cfg.Network { for _, nCfg := range v.cfg.Network {
name := nCfg.Name name := nCfg.Name