mirror of
https://github.com/luscis/openlan.git
synced 2025-10-07 01:22:51 +08:00
fea: support list/add/del/save output (#48)
This commit is contained in:
@@ -47,4 +47,5 @@ func Commands(app *api.App) {
|
||||
Log{}.Commands(app)
|
||||
Guest{}.Commands(app)
|
||||
Knock{}.Commands(app)
|
||||
Output{}.Commands(app)
|
||||
}
|
||||
|
@@ -144,6 +144,21 @@ func (u Config) Check(c *cli.Context) error {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check output config
|
||||
out.Info("%15s: %s", "check", "output")
|
||||
pattern = filepath.Join(dir, "switch", "output", "*.json")
|
||||
if files, err := filepath.Glob(pattern); err == nil {
|
||||
for _, file := range files {
|
||||
var obj []config.Output
|
||||
if err := libol.UnmarshalLoad(&obj, file); err != nil {
|
||||
out.Warn("%15s: %s", filepath.Base(file), err)
|
||||
} else {
|
||||
out.Info("%15s: %s", filepath.Base(file), "success")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
135
cmd/api/v5/output.go
Normal file
135
cmd/api/v5/output.go
Normal file
@@ -0,0 +1,135 @@
|
||||
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"
|
||||
)
|
||||
|
||||
type Output struct {
|
||||
Cmd
|
||||
}
|
||||
|
||||
func (o Output) Url(prefix, name string) string {
|
||||
return prefix + "/api/network/" + name + "/output"
|
||||
}
|
||||
|
||||
func (o Output) Add(c *cli.Context) error {
|
||||
network := c.String("network")
|
||||
if len(network) == 0 {
|
||||
return libol.NewErr("invalid network")
|
||||
}
|
||||
output := &schema.Output{
|
||||
Network: network,
|
||||
Remote: c.String("remote"),
|
||||
Segment: c.Int("segment"),
|
||||
Protocol: c.String("protocol"),
|
||||
}
|
||||
url := o.Url(c.String("url"), network)
|
||||
clt := o.NewHttp(c.String("token"))
|
||||
if err := clt.PostJSON(url, output, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o Output) Remove(c *cli.Context) error {
|
||||
network := c.String("network")
|
||||
if len(network) == 0 {
|
||||
return libol.NewErr("invalid network")
|
||||
}
|
||||
output := &schema.Output{
|
||||
Network: network,
|
||||
Device: c.String("device"),
|
||||
}
|
||||
url := o.Url(c.String("url"), network)
|
||||
clt := o.NewHttp(c.String("token"))
|
||||
if err := clt.DeleteJSON(url, output, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o Output) Save(c *cli.Context) error {
|
||||
network := c.String("network")
|
||||
url := o.Url(c.String("url"), network)
|
||||
|
||||
clt := o.NewHttp(c.String("token"))
|
||||
if err := clt.PutJSON(url, nil, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o Output) Tmpl() string {
|
||||
return `# total {{ len . }}
|
||||
{{ps -24 "network"}} {{ps -15 "protocol"}} {{ps -15 "Remote"}} {{ps -15 "segment"}} {{ps -15 "device"}}
|
||||
{{- range . }}
|
||||
{{ps -24 .Network}} {{ps -15 .Protocol}} {{ps -15 .Remote}} {{pi -15 .Segment }} {{ps -15 .Device}}
|
||||
{{- end }}
|
||||
`
|
||||
}
|
||||
|
||||
func (o Output) List(c *cli.Context) error {
|
||||
url := o.Url(c.String("url"), c.String("network"))
|
||||
clt := o.NewHttp(c.String("token"))
|
||||
var items []schema.Output
|
||||
if err := clt.GetJSON(url, &items); err != nil {
|
||||
return err
|
||||
}
|
||||
return o.Out(items, c.String("format"), o.Tmpl())
|
||||
}
|
||||
|
||||
func (o Output) Commands(app *api.App) {
|
||||
app.Command(&cli.Command{
|
||||
Name: "output",
|
||||
Aliases: []string{"op"},
|
||||
Usage: "Output configuration",
|
||||
Subcommands: []*cli.Command{
|
||||
{
|
||||
Name: "add",
|
||||
Usage: "Add an output for the network",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{Name: "network"},
|
||||
&cli.StringFlag{Name: "remote"},
|
||||
&cli.IntFlag{Name: "segment"},
|
||||
&cli.StringFlag{Name: "protocol"},
|
||||
//&cli.StringFlag{Name: "connection"},
|
||||
//&cli.StringFlag{Name: "secret"},
|
||||
//&cli.StringFlag{Name: "auth"},
|
||||
},
|
||||
Action: o.Add,
|
||||
},
|
||||
{
|
||||
Name: "remove",
|
||||
Usage: "Remove an output from the network",
|
||||
Aliases: []string{"rm"},
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{Name: "network"},
|
||||
&cli.StringFlag{Name: "device"},
|
||||
},
|
||||
Action: o.Remove,
|
||||
},
|
||||
{
|
||||
Name: "list",
|
||||
Usage: "Display all outputs of the network",
|
||||
Aliases: []string{"ls"},
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{Name: "network", Required: true},
|
||||
},
|
||||
Action: o.List,
|
||||
},
|
||||
{
|
||||
Name: "save",
|
||||
Usage: "Save all outputs",
|
||||
Aliases: []string{"sa"},
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{Name: "network", Required: true},
|
||||
},
|
||||
Action: o.Save,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
@@ -45,22 +45,5 @@
|
||||
},
|
||||
"acl": "acl-100",
|
||||
"dhcp": "enable",
|
||||
"namespace": "example",
|
||||
"outputs": [
|
||||
{
|
||||
"segment": 43,
|
||||
"remote": "3.3.3.5",
|
||||
"dstport": 8899,
|
||||
"protocol": "vxlan"
|
||||
},
|
||||
{
|
||||
"segment": 55,
|
||||
"remote": "3.3.3.3",
|
||||
"protocol": "gre"
|
||||
},
|
||||
{
|
||||
"segment": 23,
|
||||
"remote": "enp2s2"
|
||||
}
|
||||
]
|
||||
"namespace": "example"
|
||||
}
|
||||
|
@@ -12,21 +12,5 @@
|
||||
"startAt": "192.168.55.100",
|
||||
"endAt": "192.168.55.130"
|
||||
},
|
||||
"dhcp": "enable",
|
||||
"outputs": [
|
||||
{
|
||||
"segment": 43,
|
||||
"remote": "3.3.3.5",
|
||||
"protocol": "vxlan"
|
||||
},
|
||||
{
|
||||
"segment": 55,
|
||||
"remote": "3.3.3.3",
|
||||
"protocol": "gre"
|
||||
},
|
||||
{
|
||||
"segment": 23,
|
||||
"remote": "enp2s2"
|
||||
}
|
||||
]
|
||||
"dhcp": "enable"
|
||||
}
|
||||
|
17
dist/rootfs/etc/openlan/switch/output/example.json.example
vendored
Normal file
17
dist/rootfs/etc/openlan/switch/output/example.json.example
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
[
|
||||
{
|
||||
"segment": 43,
|
||||
"remote": "3.3.3.5",
|
||||
"dstport": 8899,
|
||||
"protocol": "vxlan"
|
||||
},
|
||||
{
|
||||
"segment": 55,
|
||||
"remote": "3.3.3.3",
|
||||
"protocol": "gre"
|
||||
},
|
||||
{
|
||||
"segment": 23,
|
||||
"remote": "enp2s2"
|
||||
}
|
||||
]
|
@@ -36,7 +36,7 @@ OpenLAN软件包含下面部分:
|
||||
{
|
||||
"protocol": "tcp",
|
||||
"crypt": {
|
||||
"algo": "aes-128", ## 支持xor,aes-128,aes-192等对称加密算法
|
||||
"algorithm": "aes-128", ## 支持xor,aes-128,aes-192等对称加密算法
|
||||
"secret": "ea64d5b0c96c"
|
||||
}
|
||||
}
|
||||
|
@@ -55,6 +55,12 @@ type Qoser interface {
|
||||
Save()
|
||||
}
|
||||
|
||||
type Outputer interface {
|
||||
AddOutput(segment int, protocol, Remote string)
|
||||
DelOutput(device string)
|
||||
SaveOutput()
|
||||
}
|
||||
|
||||
type Networker interface {
|
||||
String() string
|
||||
ID() string
|
||||
@@ -70,6 +76,7 @@ type Networker interface {
|
||||
Qoser() Qoser
|
||||
IfAddr() string
|
||||
ACLer() ACLer
|
||||
Outputer
|
||||
}
|
||||
|
||||
var workers = make(map[string]Networker)
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
@@ -17,6 +18,8 @@ type Output struct {
|
||||
func (h Output) Router(router *mux.Router) {
|
||||
router.HandleFunc("/api/network/{id}/output", h.Get).Methods("GET")
|
||||
router.HandleFunc("/api/network/{id}/output", h.Post).Methods("POST")
|
||||
router.HandleFunc("/api/network/{id}/output", h.Delete).Methods("DELETE")
|
||||
router.HandleFunc("/api/network/{id}/output", h.Save).Methods("PUT")
|
||||
}
|
||||
|
||||
func (h Output) Get(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -35,5 +38,65 @@ func (h Output) Get(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func (h Output) Post(w http.ResponseWriter, r *http.Request) {
|
||||
ResponseJson(w, "outputs")
|
||||
output := &schema.Output{}
|
||||
if err := GetData(r, output); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
cs := h.Switcher.Config()
|
||||
if cs.Network == nil {
|
||||
http.Error(w, "switch has no network can not add output", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
network := cs.GetNetwork(output.Network)
|
||||
if network == nil {
|
||||
http.Error(w, fmt.Sprintf("switch has no network with %s can not add output", output.Network), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
worker := GetWorker(output.Network)
|
||||
if worker == nil {
|
||||
http.Error(w, "Network not found", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
worker.AddOutput(output.Segment, output.Protocol, output.Remote)
|
||||
ResponseMsg(w, 0, "")
|
||||
}
|
||||
|
||||
func (h Output) Delete(w http.ResponseWriter, r *http.Request) {
|
||||
output := &schema.Output{}
|
||||
if err := GetData(r, output); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
cs := h.Switcher.Config()
|
||||
if cs.Network == nil {
|
||||
http.Error(w, "switch has no network can not del output", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
network := cs.GetNetwork(output.Network)
|
||||
if network == nil {
|
||||
http.Error(w, fmt.Sprintf("switch has no network with %s can not del output", output.Network), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
worker := GetWorker(output.Network)
|
||||
if worker == nil {
|
||||
http.Error(w, "Network not found", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
worker.DelOutput(output.Device)
|
||||
ResponseMsg(w, 0, "")
|
||||
}
|
||||
|
||||
func (h Output) Save(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
id := vars["id"]
|
||||
|
||||
worker := GetWorker(id)
|
||||
if worker == nil {
|
||||
http.Error(w, "Network not found", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
worker.SaveOutput()
|
||||
|
||||
ResponseJson(w, "success")
|
||||
}
|
||||
|
@@ -24,6 +24,6 @@ func Add(router *mux.Router, switcher Switcher) {
|
||||
OpenAPI{}.Router(router)
|
||||
ZTrust{}.Router(router)
|
||||
QosApi{}.Router(router)
|
||||
Output{}.Router(router)
|
||||
Output{Switcher: switcher}.Router(router)
|
||||
ACL{}.Router(router)
|
||||
}
|
||||
|
@@ -22,7 +22,7 @@ type Network struct {
|
||||
Acl string `json:"acl,omitempty"`
|
||||
Specifies interface{} `json:"specifies,omitempty"`
|
||||
Dhcp string `json:"dhcp,omitempty"`
|
||||
Outputs []Output `json:"outputs"`
|
||||
Outputs []Output `json:"outputs,omitempty"`
|
||||
ZTrust string `json:"ztrust"`
|
||||
Qos string `json:"qos,omitempty"`
|
||||
Namespace string `json:"namespace"`
|
||||
@@ -122,15 +122,26 @@ func (n *Network) LoadRoute() {
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Network) LoadOutput() {
|
||||
file := n.Dir("output", n.Name+".json")
|
||||
if err := libol.FileExist(file); err == nil {
|
||||
if err := libol.UnmarshalLoad(&n.Outputs, file); err != nil {
|
||||
libol.Error("Network.LoadOutput... %n", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Network) Save() {
|
||||
obj := *n
|
||||
obj.Routes = nil
|
||||
obj.Links = nil
|
||||
obj.Outputs = nil
|
||||
if err := libol.MarshalSave(&obj, obj.File, true); err != nil {
|
||||
libol.Error("Network.Save %s %s", obj.Name, err)
|
||||
}
|
||||
n.SaveRoute()
|
||||
n.SaveLink()
|
||||
n.SaveOutput()
|
||||
}
|
||||
|
||||
func (n *Network) SaveRoute() {
|
||||
@@ -153,6 +164,16 @@ func (n *Network) SaveLink() {
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Network) SaveOutput() {
|
||||
file := n.Dir("output", n.Name+".json")
|
||||
if n.Outputs == nil {
|
||||
return
|
||||
}
|
||||
if err := libol.MarshalSave(n.Outputs, file, true); err != nil {
|
||||
libol.Error("Network.SaveOutput %s %s", n.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Network) Reload() {
|
||||
switch n.Provider {
|
||||
case "esp":
|
||||
|
@@ -187,6 +187,7 @@ func (s *Switch) LoadNetwork() {
|
||||
}
|
||||
obj.LoadLink()
|
||||
obj.LoadRoute()
|
||||
obj.LoadOutput()
|
||||
s.Network = append(s.Network, obj)
|
||||
}
|
||||
s.Format()
|
||||
|
@@ -153,7 +153,7 @@ func (w *WorkerImpl) AddPhysical(bridge string, output string) {
|
||||
}
|
||||
}
|
||||
|
||||
func (w *WorkerImpl) AddOutput(bridge string, port *LinuxPort) {
|
||||
func (w *WorkerImpl) addOutput(bridge string, port *LinuxPort) {
|
||||
cfg := port.cfg
|
||||
out := &models.Output{
|
||||
Network: w.cfg.Name,
|
||||
@@ -210,11 +210,11 @@ func (w *WorkerImpl) AddOutput(bridge string, port *LinuxPort) {
|
||||
} else {
|
||||
link, err := nl.LinkByName(cfg.Remote)
|
||||
if link == nil {
|
||||
w.out.Error("WorkerImpl.AddOutput %s %s", cfg.Remote, err)
|
||||
w.out.Error("WorkerImpl.addOutput %s %s", cfg.Remote, err)
|
||||
return
|
||||
}
|
||||
if err := nl.LinkSetUp(link); err != nil {
|
||||
w.out.Warn("WorkerImpl.AddOutput %s %s", cfg.Remote, err)
|
||||
w.out.Warn("WorkerImpl.addOutput %s %s", cfg.Remote, err)
|
||||
}
|
||||
|
||||
if cfg.Segment > 0 {
|
||||
@@ -246,7 +246,7 @@ func (w *WorkerImpl) AddOutput(bridge string, port *LinuxPort) {
|
||||
out.Device = port.link
|
||||
cache.Output.Add(port.link, out)
|
||||
|
||||
w.out.Info("WorkerImpl.AddOutput %s %s", port.link, port.String())
|
||||
w.out.Info("WorkerImpl.addOutput %s %s", port.link, port.String())
|
||||
w.AddPhysical(bridge, port.link)
|
||||
}
|
||||
|
||||
@@ -349,7 +349,7 @@ func (w *WorkerImpl) Start(v api.Switcher) {
|
||||
port := &LinuxPort{
|
||||
cfg: output,
|
||||
}
|
||||
w.AddOutput(cfg.Bridge.Name, port)
|
||||
w.addOutput(cfg.Bridge.Name, port)
|
||||
w.outputs = append(w.outputs, port)
|
||||
}
|
||||
|
||||
@@ -425,9 +425,9 @@ func (w *WorkerImpl) DelPhysical(bridge string, output string) {
|
||||
}
|
||||
}
|
||||
|
||||
func (w *WorkerImpl) DelOutput(bridge string, port *LinuxPort) {
|
||||
func (w *WorkerImpl) delOutput(bridge string, port *LinuxPort) {
|
||||
cfg := port.cfg
|
||||
w.out.Info("WorkerImpl.DelOutput %s %s", port.link, port.String())
|
||||
w.out.Info("WorkerImpl.delOutput %s %s", port.link, port.String())
|
||||
|
||||
cache.Output.Del(port.link)
|
||||
w.DelPhysical(bridge, port.link)
|
||||
@@ -513,7 +513,7 @@ func (w *WorkerImpl) Stop() {
|
||||
}
|
||||
|
||||
for _, output := range w.outputs {
|
||||
w.DelOutput(w.cfg.Bridge.Name, output)
|
||||
w.delOutput(w.cfg.Bridge.Name, output)
|
||||
}
|
||||
w.outputs = nil
|
||||
|
||||
@@ -811,3 +811,49 @@ func (w *WorkerImpl) IfAddr() string {
|
||||
func (w *WorkerImpl) ACLer() api.ACLer {
|
||||
return w.acl
|
||||
}
|
||||
|
||||
func (w *WorkerImpl) AddOutput(segment int, protocol, Remote string) {
|
||||
output := co.Output{
|
||||
Segment: segment,
|
||||
Protocol: protocol,
|
||||
Remote: Remote,
|
||||
}
|
||||
w.cfg.Outputs = append(w.cfg.Outputs, output)
|
||||
port := &LinuxPort{
|
||||
cfg: output,
|
||||
}
|
||||
w.addOutput(w.cfg.Bridge.Name, port)
|
||||
w.outputs = append(w.outputs, port)
|
||||
}
|
||||
|
||||
func (w *WorkerImpl) DelOutput(device string) {
|
||||
var linuxport *LinuxPort
|
||||
for _, v := range w.outputs {
|
||||
if v.link == device {
|
||||
linuxport = v
|
||||
break
|
||||
}
|
||||
}
|
||||
if linuxport == nil {
|
||||
return
|
||||
}
|
||||
Outputs := make([]co.Output, 0, len(w.cfg.Outputs))
|
||||
for _, v := range w.cfg.Outputs {
|
||||
if v != linuxport.cfg {
|
||||
Outputs = append(Outputs, v)
|
||||
}
|
||||
}
|
||||
w.cfg.Outputs = Outputs
|
||||
w.delOutput(w.cfg.Bridge.Name, linuxport)
|
||||
outputs := make([]*LinuxPort, 0, len(w.outputs))
|
||||
for _, v := range w.outputs {
|
||||
if v != linuxport {
|
||||
outputs = append(outputs, v)
|
||||
}
|
||||
}
|
||||
w.outputs = outputs
|
||||
}
|
||||
|
||||
func (w *WorkerImpl) SaveOutput() {
|
||||
w.cfg.SaveOutput()
|
||||
}
|
||||
|
Reference in New Issue
Block a user