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")
format := c.String("format")
if format == "yaml" {
cfg.Format()
cfg.FormatNetwork()
}
if len(name) > 0 {
obj := cfg.GetNetwork(name)

View File

@@ -2,6 +2,7 @@ package v5
import (
"github.com/luscis/openlan/cmd/api"
"github.com/luscis/openlan/pkg/libol"
"github.com/luscis/openlan/pkg/schema"
"github.com/urfave/cli/v2"
)
@@ -11,7 +12,12 @@ type Network struct {
}
func (u Network) Url(prefix, name string) string {
return prefix + "/api/network"
if name == "" {
return prefix + "/api/network"
} else {
return prefix + "/api/network/" + name
}
}
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) {
openvpn := OpenVpn{}
app.Command(&cli.Command{
@@ -38,6 +84,32 @@ func (u Network) Commands(app *api.App) {
Aliases: []string{"ls"},
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(),
},
})

View File

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

View File

@@ -6,16 +6,21 @@ import (
"github.com/gorilla/mux"
"github.com/luscis/openlan/pkg/cache"
"github.com/luscis/openlan/pkg/libol"
"github.com/luscis/openlan/pkg/models"
"github.com/luscis/openlan/pkg/schema"
)
type Network struct {
Switcher Switcher
}
func (h Network) Router(router *mux.Router) {
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.Delete).Methods("DELETE")
router.HandleFunc("/get/network/{id}/ovpn", h.Profile).Methods("GET")
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) {
server := strings.SplitN(r.Host, ":", 2)[0]
vars := mux.Vars(r)

View File

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

View File

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

View File

@@ -50,33 +50,34 @@ func (p *Perf) Correct() {
}
type Switch struct {
File string `json:"file"`
Alias string `json:"alias"`
Perf Perf `json:"limit,omitempty"`
Protocol string `json:"protocol"` // tcp, tls, udp, kcp, ws and wss.
Listen string `json:"listen"`
Timeout int `json:"timeout"`
Http *Http `json:"http,omitempty"`
Log Log `json:"log"`
Cert *Cert `json:"cert,omitempty"`
Crypt *Crypt `json:"crypt,omitempty"`
Network []*Network `json:"network,omitempty"`
Acl map[string]*ACL `json:"acl,omitempty"`
Qos map[string]*Qos `json:"qos,omitempty"`
FireWall []FlowRule `json:"firewall,omitempty"`
Queue Queue `json:"queue"`
PassFile string `json:"password"`
Ldap *LDAP `json:"ldap,omitempty"`
AddrPool string `json:"pool,omitempty"`
ConfDir string `json:"-"`
TokenFile string `json:"-"`
L2TP *L2TP `json:"l2tp"`
File string `json:"file"`
Alias string `json:"alias"`
Perf Perf `json:"limit,omitempty"`
Protocol string `json:"protocol"` // tcp, tls, udp, kcp, ws and wss.
Listen string `json:"listen"`
Timeout int `json:"timeout"`
Http *Http `json:"http,omitempty"`
Log Log `json:"log"`
Cert *Cert `json:"cert,omitempty"`
Crypt *Crypt `json:"crypt,omitempty"`
Network map[string]*Network `json:"network,omitempty"`
Acl map[string]*ACL `json:"acl,omitempty"`
Qos map[string]*Qos `json:"qos,omitempty"`
FireWall []FlowRule `json:"firewall,omitempty"`
Queue Queue `json:"queue"`
PassFile string `json:"password"`
Ldap *LDAP `json:"ldap,omitempty"`
AddrPool string `json:"pool,omitempty"`
ConfDir string `json:"-"`
TokenFile string `json:"-"`
L2TP *L2TP `json:"l2tp"`
}
func NewSwitch() *Switch {
s := &Switch{
Acl: make(map[string]*ACL, 32),
Qos: make(map[string]*Qos, 1024),
Acl: make(map[string]*ACL, 32),
Qos: make(map[string]*Qos, 1024),
Network: make(map[string]*Network, 32),
}
s.Parse()
s.Initialize()
@@ -155,19 +156,77 @@ func (s *Switch) Dir(elem ...string) string {
return filepath.Join(args...)
}
func (s *Switch) Format() {
for _, obj := range s.Network {
context := obj.Specifies
obj.NewSpecifies()
if obj.Specifies == nil {
continue
}
if data, err := libol.Marshal(context, true); err != nil {
libol.Warn("Switch.Format %s", err)
} else if err := libol.Unmarshal(obj.Specifies, data); err != nil {
libol.Warn("Switch.Format %s", err)
}
func (s *Switch) formatNetworkWithObj(obj *Network) {
context := obj.Specifies
obj.NewSpecifies()
if obj.Specifies == nil {
return
}
if data, err := libol.Marshal(context, true); err != nil {
libol.Warn("Switch.Format %s", err)
} else if err := libol.Unmarshal(obj.Specifies, data); err != nil {
libol.Warn("Switch.Format %s", err)
}
}
func (s *Switch) FormatNetwork() {
for _, obj := range s.Network {
s.formatNetworkWithObj(obj)
}
}
func (s *Switch) LoadNetworkWithFile(file string) {
obj := &Network{
Alias: s.Alias,
File: file,
ConfDir: s.ConfDir,
}
if err := libol.UnmarshalLoad(obj, file); err != nil {
libol.Error("Switch.LoadNetwork %s", err)
return
}
obj.LoadLink()
obj.LoadRoute()
obj.LoadOutput()
s.Network[obj.Name] = obj
}
func (s *Switch) correctNetworkWithObj(obj *Network) {
for _, link := range obj.Links {
link.Correct()
}
obj.Correct(s)
obj.Alias = s.Alias
if obj.File == "" {
obj.File = s.Dir("network", obj.Name+".json")
}
if _, ok := s.Acl[obj.Name]; !ok {
obj := &ACL{
Name: obj.Name,
}
obj.Correct(s)
s.Acl[obj.Name] = obj
}
if _, ok := s.Qos[obj.Name]; !ok {
obj := &Qos{
Name: obj.Name,
}
obj.Correct(s)
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() {
@@ -176,45 +235,10 @@ func (s *Switch) LoadNetwork() {
libol.Error("Switch.LoadNetwork %s", err)
}
for _, k := range files {
obj := &Network{
Alias: s.Alias,
File: k,
ConfDir: s.ConfDir,
}
if err := libol.UnmarshalLoad(obj, k); err != nil {
libol.Error("Switch.LoadNetwork %s", err)
continue
}
obj.LoadLink()
obj.LoadRoute()
obj.LoadOutput()
s.Network = append(s.Network, obj)
}
s.Format()
for _, obj := range s.Network {
for _, link := range obj.Links {
link.Correct()
}
obj.Correct(s)
obj.Alias = s.Alias
if obj.File == "" {
obj.File = s.Dir("network", obj.Name+".json")
}
if _, ok := s.Acl[obj.Name]; !ok {
obj := &ACL{
Name: obj.Name,
}
obj.Correct(s)
s.Acl[obj.Name] = obj
}
if _, ok := s.Qos[obj.Name]; !ok {
obj := &Qos{
Name: obj.Name,
}
obj.Correct(s)
s.Qos[obj.Name] = obj
}
s.LoadNetworkWithFile(k)
}
s.FormatNetwork()
s.CorrectNetwork()
}
func (s *Switch) LoadQos() {
@@ -304,8 +328,12 @@ func (s *Switch) Reload() {
}
func (s *Switch) GetNetwork(name string) *Network {
return s.Network[name]
}
func (s *Switch) GetNetworkWithFile(file string) *Network {
for _, obj := range s.Network {
if obj.Name == name {
if obj.File == file {
return obj
}
}

View File

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

View File

@@ -2,6 +2,7 @@ package cswitch
import (
"encoding/json"
"os"
"os/exec"
"strconv"
"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() {
for _, nCfg := range v.cfg.Network {
name := nCfg.Name