mirror of
https://github.com/luscis/openlan.git
synced 2025-10-05 08:36:59 +08:00
fea:support add/del/save network (#55)
* fea:support add/del/save network
This commit is contained in:
@@ -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)
|
||||
|
@@ -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(),
|
||||
},
|
||||
})
|
||||
|
@@ -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 {
|
||||
|
@@ -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)
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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)
|
||||
|
@@ -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
|
||||
}
|
||||
}
|
||||
|
@@ -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"`
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user