| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178 |
- package cli
- import (
- "sort"
- "strings"
- "sync"
- "time"
- )
- // TerminalWriter is an interface satisfied by *terminal.Terminal and mock terminals.
- type TerminalWriter interface {
- Write(buf []byte) (n int, err error)
- }
- // Node represents a command or subsection in the CLI hierarchy.
- type Node struct {
- Name string
- Aliases []string
- Description string
- Children []*Node
- Dynamic func() []string
- }
- // AddChild appends a child node to this node and returns the child.
- func (n *Node) AddChild(child *Node) *Node {
- n.Children = append(n.Children, child)
- return child
- }
- // FindChild searches for a child matching token by Name, Aliases, or unique prefix.
- func (n *Node) FindChild(token string) *Node {
- token = strings.ToLower(token)
- // 1. Exact Name match
- for _, ch := range n.Children {
- if strings.ToLower(ch.Name) == token {
- return ch
- }
- }
- // 2. Exact Aliases match
- for _, ch := range n.Children {
- for _, a := range ch.Aliases {
- if strings.ToLower(a) == token {
- return ch
- }
- }
- }
- // 3. Unique prefix match among children (excluding parameters ending in '=')
- var match *Node
- for _, ch := range n.Children {
- if !strings.HasSuffix(ch.Name, "=") && strings.HasPrefix(strings.ToLower(ch.Name), token) {
- if match != nil {
- return nil // Ambiguous
- }
- match = ch
- }
- }
- return match
- }
- // Completer manages tab-completion state and double-tab candidate listing.
- type Completer struct {
- term TerminalWriter
- executor *Executor
- root *Node
- termWidth int
- mu sync.Mutex
- lastTabTime time.Time
- lastTabLine string
- lastTabPos int
- }
- // NewCompleter creates and initializes a Completer with the full command tree.
- func NewCompleter(term TerminalWriter, executor *Executor) *Completer {
- c := &Completer{
- term: term,
- executor: executor,
- termWidth: 80,
- }
- c.root = c.buildCommandTree()
- return c
- }
- // SetWidth sets the terminal width for candidate column formatting.
- func (c *Completer) SetWidth(w int) {
- c.mu.Lock()
- defer c.mu.Unlock()
- if w > 20 {
- c.termWidth = w
- }
- }
- // Callback is the AutoCompleteCallback for golang.org/x/term.Terminal.
- func (c *Completer) Callback(line string, pos int, key rune) (newLine string, newPos int, ok bool) {
- if key != '\t' {
- return "", 0, false
- }
- c.mu.Lock()
- defer c.mu.Unlock()
- candidates, prefixBeforeWord, currentWord, isParamVal, paramPrefix := c.getCompletions(line, pos)
- if len(candidates) == 0 {
- // Nothing to complete
- c.lastTabTime = time.Time{}
- c.lastTabLine = ""
- c.lastTabPos = 0
- return "", 0, false
- }
- suffix := ""
- if pos < len(line) {
- suffix = line[pos:]
- }
- // Single match: complete it immediately!
- if len(candidates) == 1 {
- c.lastTabTime = time.Time{}
- c.lastTabLine = ""
- c.lastTabPos = 0
- match := candidates[0]
- completedToken := match
- if isParamVal {
- completedToken = paramPrefix + match + " "
- } else if strings.HasSuffix(match, "=") {
- // Parameter key, e.g. "address=" -> no trailing space
- completedToken = match
- } else {
- completedToken = match + " "
- }
- newLine = prefixBeforeWord + completedToken + suffix
- newPos = len(prefixBeforeWord) + len(completedToken)
- return newLine, newPos, true
- }
- // Multiple candidates: find Longest Common Prefix (LCP)
- lcp := longestCommonPrefix(candidates)
- targetWord := currentWord
- if isParamVal {
- targetWord = currentWord[len(paramPrefix):]
- }
- // If LCP can extend the current input, expand it
- if len(lcp) > len(targetWord) {
- extendedToken := lcp
- if isParamVal {
- extendedToken = paramPrefix + lcp
- }
- newLine = prefixBeforeWord + extendedToken + suffix
- newPos = len(prefixBeforeWord) + len(extendedToken)
- // Record tab state so an immediate second tab shows remaining options
- c.lastTabTime = time.Now()
- c.lastTabLine = newLine
- c.lastTabPos = newPos
- return newLine, newPos, true
- }
- // LCP cannot extend input further: check for 2nd Tab (within 1000ms)
- isSecondTab := time.Since(c.lastTabTime) <= 1000*time.Millisecond &&
- c.lastTabLine == line &&
- c.lastTabPos == pos
- if !isSecondTab {
- // 1st Tab: Record state and wait for potential 2nd Tab
- c.lastTabTime = time.Now()
- c.lastTabLine = line
- c.lastTabPos = pos
- return line, pos, true
- }
- // 2nd Tab: DISPLAY ALL CANDIDATES!
- c.lastTabTime = time.Time{}
- c.lastTabLine = ""
- c.lastTabPos = 0
- if c.term != nil {
- formatted := c.formatCandidates(candidates)
- _, _ = c.term.Write([]byte(formatted))
- }
- return line, pos, true
- }
- // getCompletions computes the candidate completions for the current cursor context.
- func (c *Completer) getCompletions(line string, pos int) (candidates []string, prefixBeforeWord string, currentWord string, isParamVal bool, paramPrefix string) {
- if pos > len(line) {
- pos = len(line)
- }
- input := line[:pos]
- lastSpace := strings.LastIndexAny(input, " \t")
- if lastSpace == -1 {
- // Single word so far (or empty)
- if strings.HasPrefix(input, "/") {
- prefixBeforeWord = "/"
- currentWord = input[1:]
- } else {
- prefixBeforeWord = ""
- currentWord = input
- }
- } else {
- prefixBeforeWord = input[:lastSpace+1]
- currentWord = input[lastSpace+1:]
- }
- // Parse preceding words to navigate tree
- rawPrefix := strings.TrimSpace(prefixBeforeWord)
- hasSlash := strings.HasPrefix(rawPrefix, "/")
- if hasSlash {
- rawPrefix = strings.TrimPrefix(rawPrefix, "/")
- }
- var precedingTokens []string
- if rawPrefix != "" {
- precedingTokens = strings.Fields(rawPrefix)
- }
- // Traverse tree to find current node and track used parameter keys
- currNode := c.root
- usedParams := make(map[string]bool)
- for _, token := range precedingTokens {
- if idx := strings.Index(token, "="); idx != -1 {
- // Parameter key=value, stay at current node
- key := strings.ToLower(token[:idx+1])
- usedParams[key] = true
- continue
- }
- next := currNode.FindChild(token)
- if next != nil {
- currNode = next
- }
- }
- // Check if user is typing a parameter value (e.g. "interface=eth" or "role=")
- if idx := strings.Index(currentWord, "="); idx != -1 {
- paramKey := strings.ToLower(currentWord[:idx+1])
- paramVal := strings.ToLower(currentWord[idx+1:])
- paramChild := currNode.FindChild(paramKey)
- if paramChild != nil && paramChild.Dynamic != nil {
- isParamVal = true
- paramPrefix = currentWord[:idx+1]
- for _, val := range paramChild.Dynamic() {
- if strings.HasPrefix(strings.ToLower(val), paramVal) {
- candidates = append(candidates, val)
- }
- }
- sort.Strings(candidates)
- return
- }
- }
- // Gather child commands and parameters
- search := strings.ToLower(currentWord)
- for _, ch := range currNode.Children {
- nameLower := strings.ToLower(ch.Name)
- if strings.HasSuffix(nameLower, "=") {
- if usedParams[nameLower] {
- continue // parameter already provided
- }
- }
- if strings.HasPrefix(nameLower, search) {
- candidates = append(candidates, ch.Name)
- }
- }
- // Check if current node has dynamic positional choices (e.g. interface names or service names)
- if currNode.Dynamic != nil {
- for _, dyn := range currNode.Dynamic() {
- if strings.HasPrefix(strings.ToLower(dyn), search) {
- candidates = append(candidates, dyn)
- }
- }
- }
- // Deduplicate and sort
- candidates = uniqueStrings(candidates)
- sort.Strings(candidates)
- return
- }
- func (c *Completer) formatCandidates(candidates []string) string {
- if len(candidates) == 0 {
- return ""
- }
- termWidth := c.termWidth
- if termWidth < 40 {
- termWidth = 80
- }
- maxLen := 0
- for _, cand := range candidates {
- if len(cand) > maxLen {
- maxLen = len(cand)
- }
- }
- colWidth := maxLen + 3
- if colWidth < 10 {
- colWidth = 10
- }
- numCols := (termWidth - 4) / colWidth
- if numCols < 1 {
- numCols = 1
- }
- if numCols > len(candidates) {
- numCols = len(candidates)
- }
- numRows := (len(candidates) + numCols - 1) / numCols
- var sb strings.Builder
- sb.WriteString("\n")
- for r := 0; r < numRows; r++ {
- sb.WriteString(" ")
- for col := 0; col < numCols; col++ {
- idx := col*numRows + r
- if idx < len(candidates) {
- cand := candidates[idx]
- colored := colorizeCandidate(cand)
- sb.WriteString(colored)
- if col < numCols-1 && (col+1)*numRows+r < len(candidates) {
- pad := colWidth - len(cand)
- if pad > 0 {
- sb.WriteString(strings.Repeat(" ", pad))
- }
- }
- }
- }
- sb.WriteString("\n")
- }
- return sb.String()
- }
- func colorizeCandidate(s string) string {
- if strings.HasSuffix(s, "=") {
- return ColorYellow + s + ColorReset
- }
- switch s {
- case "print", "add", "remove", "enable", "disable", "set", "reboot", "flush", "renew", "release", "connect", "disconnect", "status":
- return ColorGreen + s + ColorReset
- case "interface", "ip", "routing", "tool", "log", "user", "system", "certificate", "certificates",
- "vlan", "bridge", "wireguard", "eoip", "vxlan", "vrrp", "pppoe-client",
- "address", "route", "dhcp-client", "dhcp-server", "dns", "firewall", "service", "reverse-proxy", "sdwan", "sd-wan", "member", "members",
- "filter", "nat", "mangle", "address-list", "bgp", "ospf", "port", "peers", "lease", "network", "cache", "static", "rule", "table", "instance", "area", "neighbor", "resource", "identity":
- return ColorCyan + s + ColorReset
- case "www", "www-ssl", "ssh", "telnet", "web", "web-ssl":
- return ColorMagenta + s + ColorReset
- default:
- return ColorWhite + s + ColorReset
- }
- }
- func longestCommonPrefix(strs []string) string {
- if len(strs) == 0 {
- return ""
- }
- prefix := strs[0]
- for _, s := range strs[1:] {
- for !strings.HasPrefix(strings.ToLower(s), strings.ToLower(prefix)) {
- if len(prefix) == 0 {
- return ""
- }
- prefix = prefix[:len(prefix)-1]
- }
- }
- return prefix
- }
- func uniqueStrings(slice []string) []string {
- seen := make(map[string]bool)
- var result []string
- for _, s := range slice {
- if !seen[s] {
- seen[s] = true
- result = append(result, s)
- }
- }
- return result
- }
- // buildCommandTree creates the full tree of commands, subsections, actions, parameters, and dynamic providers.
- func (c *Completer) buildCommandTree() *Node {
- root := &Node{Name: "root"}
- // Helper for dynamic interfaces
- dynInterfaces := func() []string {
- if c.executor != nil && c.executor.netMgr != nil {
- ifaces, err := c.executor.netMgr.ListInterfaces()
- if err == nil {
- var names []string
- for _, iface := range ifaces {
- names = append(names, iface.Name)
- }
- return names
- }
- }
- return []string{"eth0", "eth1", "lo"}
- }
- // Helper for services
- dynServices := func() []string {
- if c.executor != nil && c.executor.servicesMgr != nil {
- var names []string
- for _, s := range c.executor.servicesMgr.ListServices() {
- names = append(names, s.Name)
- }
- return names
- }
- return []string{"www", "www-ssl", "telnet", "ssh"}
- }
- // Helper for certificates
- dynCertificates := func() []string {
- if c.executor != nil && c.executor.certMgr != nil {
- var names []string
- for _, cert := range c.executor.certMgr.ListCertificates() {
- names = append(names, cert.Name)
- }
- return names
- }
- return nil
- }
- dynCAs := func() []string {
- if c.executor != nil && c.executor.certMgr != nil {
- var names []string
- for _, cert := range c.executor.certMgr.ListCertificates() {
- if cert.IsCA {
- names = append(names, cert.Name)
- }
- }
- return names
- }
- return nil
- }
- dynSDWANGroups := func() []string {
- if c.executor != nil && c.executor.sdwanMgr != nil {
- var names []string
- for _, g := range c.executor.sdwanMgr.List() {
- names = append(names, g.Name)
- }
- return names
- }
- return nil
- }
- // Common standard actions
- addPrint := func(n *Node) {
- n.AddChild(&Node{Name: "print", Aliases: []string{"pr", "show", "list"}})
- }
- addRemove := func(n *Node) {
- n.AddChild(&Node{Name: "remove", Aliases: []string{"rem", "delete"}})
- }
- addEnableDisable := func(n *Node) {
- n.AddChild(&Node{Name: "enable"})
- n.AddChild(&Node{Name: "disable"})
- }
- // 1. /interface
- ifaceNode := root.AddChild(&Node{Name: "interface", Aliases: []string{"interfaces"}})
- addPrint(ifaceNode)
- ifaceNode.AddChild(&Node{Name: "enable", Dynamic: dynInterfaces})
- ifaceNode.AddChild(&Node{Name: "disable", Dynamic: dynInterfaces})
- ifaceSet := ifaceNode.AddChild(&Node{Name: "set", Dynamic: dynInterfaces})
- ifaceSet.AddChild(&Node{Name: "mtu="})
- // /interface vlan
- vlanNode := ifaceNode.AddChild(&Node{Name: "vlan", Aliases: []string{"vlans"}})
- addPrint(vlanNode)
- addRemove(vlanNode)
- vlanAdd := vlanNode.AddChild(&Node{Name: "add"})
- vlanAdd.AddChild(&Node{Name: "name="})
- vlanAdd.AddChild(&Node{Name: "vlan-id="})
- vlanAdd.AddChild(&Node{Name: "interface=", Dynamic: dynInterfaces})
- // /interface bridge
- bridgeNode := ifaceNode.AddChild(&Node{Name: "bridge", Aliases: []string{"bridges"}})
- addPrint(bridgeNode)
- addRemove(bridgeNode)
- addEnableDisable(bridgeNode)
- bridgeAdd := bridgeNode.AddChild(&Node{Name: "add"})
- bridgeAdd.AddChild(&Node{Name: "name="})
- // /interface bridge port
- bridgePortNode := bridgeNode.AddChild(&Node{Name: "port", Aliases: []string{"ports"}})
- addPrint(bridgePortNode)
- addRemove(bridgePortNode)
- addEnableDisable(bridgePortNode)
- bridgePortAdd := bridgePortNode.AddChild(&Node{Name: "add"})
- bridgePortAdd.AddChild(&Node{Name: "bridge="})
- bridgePortAdd.AddChild(&Node{Name: "interface=", Dynamic: dynInterfaces})
- bridgePortAdd.AddChild(&Node{Name: "pvid="})
- // /interface wireguard
- wgNode := ifaceNode.AddChild(&Node{Name: "wireguard", Aliases: []string{"wg"}})
- addPrint(wgNode)
- addRemove(wgNode)
- addEnableDisable(wgNode)
- wgAdd := wgNode.AddChild(&Node{Name: "add"})
- wgAdd.AddChild(&Node{Name: "name="})
- wgAdd.AddChild(&Node{Name: "listen-port="})
- wgAdd.AddChild(&Node{Name: "private-key="})
- // /interface wireguard peers
- wgPeers := wgNode.AddChild(&Node{Name: "peers", Aliases: []string{"peer"}})
- addPrint(wgPeers)
- addRemove(wgPeers)
- wgPeersAdd := wgPeers.AddChild(&Node{Name: "add"})
- wgPeersAdd.AddChild(&Node{Name: "interface=", Dynamic: dynInterfaces})
- wgPeersAdd.AddChild(&Node{Name: "public-key="})
- wgPeersAdd.AddChild(&Node{Name: "allowed-address="})
- wgPeersAdd.AddChild(&Node{Name: "endpoint-address="})
- wgPeersAdd.AddChild(&Node{Name: "endpoint-port="})
- // /interface aerotun
- aero := ifaceNode.AddChild(&Node{Name: "aerotun"})
- names := func() []string {
- if c.executor.vpnMgr == nil || c.executor.vpnMgr.AeroTUN == nil {
- return nil
- }
- var out []string
- for _, inst := range c.executor.vpnMgr.AeroTUN.List() {
- out = append(out, inst.Name)
- }
- return out
- }
- aero.AddChild(&Node{Name: "print"}).AddChild(&Node{Name: "detail="})
- aero.AddChild(&Node{Name: "genkey"})
- for _, action := range []string{"add", "set", "remove", "enable", "disable", "start", "stop"} {
- n := aero.AddChild(&Node{Name: action, Dynamic: names})
- if action == "add" || action == "set" {
- for _, param := range []string{"name=", "protocol=", "mode=", "listen-port=", "endpoint=", "local-address=", "peer-address=", "peer-public-key=", "allowed-ips=", "psk=", "mtu=", "disabled=", "compression=", "default-route=", "comment="} {
- n.AddChild(&Node{Name: param})
- }
- }
- }
- // /interface eoip
- eoipNode := ifaceNode.AddChild(&Node{Name: "eoip"})
- addPrint(eoipNode)
- addRemove(eoipNode)
- addEnableDisable(eoipNode)
- eoipAdd := eoipNode.AddChild(&Node{Name: "add"})
- eoipAdd.AddChild(&Node{Name: "name="})
- eoipAdd.AddChild(&Node{Name: "remote-ip="})
- eoipAdd.AddChild(&Node{Name: "tunnel-id="})
- // /interface vxlan
- vxlanNode := ifaceNode.AddChild(&Node{Name: "vxlan"})
- addPrint(vxlanNode)
- addRemove(vxlanNode)
- addEnableDisable(vxlanNode)
- vxlanAdd := vxlanNode.AddChild(&Node{Name: "add"})
- for _, p := range []string{"name=", "vni=", "port=", "mtu=", "mac-address=", "local-address=", "remote-address=", "group=", "interface=", "learning=", "comment="} {
- vxlanAdd.AddChild(&Node{Name: p})
- }
- vxlanSet := vxlanNode.AddChild(&Node{Name: "set"})
- for _, p := range []string{"name=", "vni=", "port=", "mtu=", "mac-address=", "local-address=", "remote-address=", "group=", "interface=", "comment="} {
- vxlanSet.AddChild(&Node{Name: p})
- }
- vtepsNode := vxlanNode.AddChild(&Node{Name: "vteps"})
- addPrint(vtepsNode)
- addRemove(vtepsNode)
- vtepsAdd := vtepsNode.AddChild(&Node{Name: "add"})
- vtepsAdd.AddChild(&Node{Name: "interface="})
- vtepsAdd.AddChild(&Node{Name: "remote-ip="})
- vtepsAdd.AddChild(&Node{Name: "port="})
- vtepsAdd.AddChild(&Node{Name: "comment="})
- // /interface vrrp
- vrrpNode := ifaceNode.AddChild(&Node{Name: "vrrp"})
- addPrint(vrrpNode)
- addRemove(vrrpNode)
- addEnableDisable(vrrpNode)
- vrrpAdd := vrrpNode.AddChild(&Node{Name: "add"})
- vrrpAdd.AddChild(&Node{Name: "name="})
- vrrpAdd.AddChild(&Node{Name: "interface=", Dynamic: dynInterfaces})
- vrrpAdd.AddChild(&Node{Name: "vrid="})
- vrrpAdd.AddChild(&Node{Name: "priority="})
- // /interface pppoe-client
- pppoeNode := ifaceNode.AddChild(&Node{Name: "pppoe-client"})
- addPrint(pppoeNode)
- addRemove(pppoeNode)
- pppoeNode.AddChild(&Node{Name: "connect"})
- pppoeNode.AddChild(&Node{Name: "disconnect"})
- pppoeAdd := pppoeNode.AddChild(&Node{Name: "add"})
- pppoeAdd.AddChild(&Node{Name: "name="})
- pppoeAdd.AddChild(&Node{Name: "interface=", Dynamic: dynInterfaces})
- pppoeAdd.AddChild(&Node{Name: "user="})
- pppoeAdd.AddChild(&Node{Name: "password="})
- // 2. /ip
- ipNode := root.AddChild(&Node{Name: "ip"})
- // /ip address
- ipAddrNode := ipNode.AddChild(&Node{Name: "address", Aliases: []string{"addr"}})
- addPrint(ipAddrNode)
- addRemove(ipAddrNode)
- ipAddrAdd := ipAddrNode.AddChild(&Node{Name: "add"})
- ipAddrAdd.AddChild(&Node{Name: "address="})
- ipAddrAdd.AddChild(&Node{Name: "interface=", Dynamic: dynInterfaces})
- ipAddrAdd.AddChild(&Node{Name: "network="})
- // /ip route
- ipRouteNode := ipNode.AddChild(&Node{Name: "route", Aliases: []string{"routes"}})
- addPrint(ipRouteNode)
- addRemove(ipRouteNode)
- addEnableDisable(ipRouteNode)
- ipRouteAdd := ipRouteNode.AddChild(&Node{Name: "add"})
- ipRouteAdd.AddChild(&Node{Name: "dst-address="})
- ipRouteAdd.AddChild(&Node{Name: "gateway=", Dynamic: dynInterfaces})
- ipRouteAdd.AddChild(&Node{Name: "interface=", Dynamic: dynInterfaces})
- ipRouteAdd.AddChild(&Node{Name: "distance="})
- // /ip route rule
- ipRouteRule := ipRouteNode.AddChild(&Node{Name: "rule", Aliases: []string{"rules"}})
- addPrint(ipRouteRule)
- addRemove(ipRouteRule)
- ipRouteRuleAdd := ipRouteRule.AddChild(&Node{Name: "add"})
- ipRouteRuleAdd.AddChild(&Node{Name: "src-address="})
- ipRouteRuleAdd.AddChild(&Node{Name: "dst-address="})
- ipRouteRuleAdd.AddChild(&Node{Name: "table="})
- ipRouteRuleAdd.AddChild(&Node{Name: "action=", Dynamic: func() []string { return []string{"lookup", "unreachable", "drop"} }})
- // /ip route table
- ipRouteTable := ipRouteNode.AddChild(&Node{Name: "table", Aliases: []string{"tables"}})
- addPrint(ipRouteTable)
- addRemove(ipRouteTable)
- ipRouteTableAdd := ipRouteTable.AddChild(&Node{Name: "add"})
- ipRouteTableAdd.AddChild(&Node{Name: "name="})
- ipRouteTableAdd.AddChild(&Node{Name: "fib="})
- // /ip dhcp-client
- dhcpCliNode := ipNode.AddChild(&Node{Name: "dhcp-client"})
- addPrint(dhcpCliNode)
- addRemove(dhcpCliNode)
- dhcpCliNode.AddChild(&Node{Name: "renew"})
- dhcpCliNode.AddChild(&Node{Name: "release"})
- dhcpCliAdd := dhcpCliNode.AddChild(&Node{Name: "add"})
- dhcpCliAdd.AddChild(&Node{Name: "interface=", Dynamic: dynInterfaces})
- dhcpCliAdd.AddChild(&Node{Name: "disabled=", Dynamic: func() []string { return []string{"yes", "no"} }})
- // /ip dhcp-server
- dhcpSrvNode := ipNode.AddChild(&Node{Name: "dhcp-server"})
- addPrint(dhcpSrvNode)
- addRemove(dhcpSrvNode)
- addEnableDisable(dhcpSrvNode)
- dhcpSrvAdd := dhcpSrvNode.AddChild(&Node{Name: "add"})
- dhcpSrvAdd.AddChild(&Node{Name: "name="})
- dhcpSrvAdd.AddChild(&Node{Name: "interface=", Dynamic: dynInterfaces})
- dhcpSrvAdd.AddChild(&Node{Name: "address-pool="})
- dhcpSrvAdd.AddChild(&Node{Name: "lease-time="})
- // /ip dhcp-server lease
- dhcpLeaseNode := dhcpSrvNode.AddChild(&Node{Name: "lease", Aliases: []string{"leases"}})
- addPrint(dhcpLeaseNode)
- addRemove(dhcpLeaseNode)
- // /ip dhcp-server network
- dhcpNetNode := dhcpSrvNode.AddChild(&Node{Name: "network", Aliases: []string{"networks"}})
- addPrint(dhcpNetNode)
- addRemove(dhcpNetNode)
- dhcpNetAdd := dhcpNetNode.AddChild(&Node{Name: "add"})
- dhcpNetAdd.AddChild(&Node{Name: "address="})
- dhcpNetAdd.AddChild(&Node{Name: "gateway="})
- dhcpNetAdd.AddChild(&Node{Name: "dns-server="})
- // /ip dns
- dnsNode := ipNode.AddChild(&Node{Name: "dns"})
- addPrint(dnsNode)
- dnsSet := dnsNode.AddChild(&Node{Name: "set"})
- dnsSet.AddChild(&Node{Name: "servers="})
- dnsSet.AddChild(&Node{Name: "allow-remote-requests=", Dynamic: func() []string { return []string{"yes", "no"} }})
- dnsCache := dnsNode.AddChild(&Node{Name: "cache"})
- addPrint(dnsCache)
- dnsCache.AddChild(&Node{Name: "flush"})
- dnsStatic := dnsNode.AddChild(&Node{Name: "static"})
- addPrint(dnsStatic)
- addRemove(dnsStatic)
- dnsStaticAdd := dnsStatic.AddChild(&Node{Name: "add"})
- dnsStaticAdd.AddChild(&Node{Name: "name="})
- dnsStaticAdd.AddChild(&Node{Name: "address="})
- // /ip firewall
- fwNode := ipNode.AddChild(&Node{Name: "firewall"})
- // /ip firewall filter
- fwFilter := fwNode.AddChild(&Node{Name: "filter"})
- addPrint(fwFilter)
- addRemove(fwFilter)
- addEnableDisable(fwFilter)
- fwFilterAdd := fwFilter.AddChild(&Node{Name: "add"})
- fwFilterAdd.AddChild(&Node{Name: "chain=", Dynamic: func() []string { return []string{"forward", "input", "output"} }})
- fwFilterAdd.AddChild(&Node{Name: "action=", Dynamic: func() []string { return []string{"accept", "drop", "reject"} }})
- fwFilterAdd.AddChild(&Node{Name: "protocol=", Dynamic: func() []string { return []string{"icmp", "tcp", "udp"} }})
- fwFilterAdd.AddChild(&Node{Name: "src-address="})
- fwFilterAdd.AddChild(&Node{Name: "dst-address="})
- fwFilterAdd.AddChild(&Node{Name: "dst-port="})
- fwFilterAdd.AddChild(&Node{Name: "in-interface=", Dynamic: dynInterfaces})
- fwFilterAdd.AddChild(&Node{Name: "out-interface=", Dynamic: dynInterfaces})
- fwFilterAdd.AddChild(&Node{Name: "comment="})
- // /ip firewall nat
- fwNat := fwNode.AddChild(&Node{Name: "nat"})
- addPrint(fwNat)
- addRemove(fwNat)
- addEnableDisable(fwNat)
- fwNatAdd := fwNat.AddChild(&Node{Name: "add"})
- fwNatAdd.AddChild(&Node{Name: "chain=", Dynamic: func() []string { return []string{"dstnat", "srcnat"} }})
- fwNatAdd.AddChild(&Node{Name: "action=", Dynamic: func() []string { return []string{"accept", "dst-nat", "masquerade", "redirect", "src-nat"} }})
- fwNatAdd.AddChild(&Node{Name: "protocol=", Dynamic: func() []string { return []string{"icmp", "tcp", "udp"} }})
- fwNatAdd.AddChild(&Node{Name: "src-address="})
- fwNatAdd.AddChild(&Node{Name: "dst-address="})
- fwNatAdd.AddChild(&Node{Name: "to-addresses="})
- fwNatAdd.AddChild(&Node{Name: "to-ports="})
- fwNatAdd.AddChild(&Node{Name: "out-interface=", Dynamic: dynInterfaces})
- fwNatAdd.AddChild(&Node{Name: "comment="})
- // /ip firewall mangle
- fwMangle := fwNode.AddChild(&Node{Name: "mangle"})
- addPrint(fwMangle)
- addRemove(fwMangle)
- addEnableDisable(fwMangle)
- fwMangleAdd := fwMangle.AddChild(&Node{Name: "add"})
- fwMangleAdd.AddChild(&Node{Name: "chain=", Dynamic: func() []string { return []string{"forward", "input", "output", "postrouting", "prerouting"} }})
- fwMangleAdd.AddChild(&Node{Name: "action=", Dynamic: func() []string { return []string{"accept", "mark-packet", "mark-routing"} }})
- fwMangleAdd.AddChild(&Node{Name: "protocol=", Dynamic: func() []string { return []string{"icmp", "tcp", "udp"} }})
- fwMangleAdd.AddChild(&Node{Name: "src-address="})
- fwMangleAdd.AddChild(&Node{Name: "dst-address="})
- // /ip firewall address-list
- fwAddrList := fwNode.AddChild(&Node{Name: "address-list"})
- addPrint(fwAddrList)
- addRemove(fwAddrList)
- addEnableDisable(fwAddrList)
- fwAddrListAdd := fwAddrList.AddChild(&Node{Name: "add"})
- fwAddrListAdd.AddChild(&Node{Name: "list="})
- fwAddrListAdd.AddChild(&Node{Name: "address="})
- fwAddrListAdd.AddChild(&Node{Name: "comment="})
- // /ip firewall connection
- fwConn := fwNode.AddChild(&Node{Name: "connection", Aliases: []string{"connections"}})
- addPrint(fwConn)
- // /ip service
- serviceNode := ipNode.AddChild(&Node{Name: "service", Aliases: []string{"services"}})
- addPrint(serviceNode)
- serviceNode.AddChild(&Node{Name: "enable", Dynamic: dynServices})
- serviceNode.AddChild(&Node{Name: "disable", Dynamic: dynServices})
- serviceSet := serviceNode.AddChild(&Node{Name: "set", Dynamic: dynServices})
- serviceSet.AddChild(&Node{Name: "port="})
- serviceSet.AddChild(&Node{Name: "disabled=", Dynamic: func() []string { return []string{"yes", "no"} }})
- serviceSet.AddChild(&Node{Name: "certificate=", Dynamic: dynCertificates})
- // /ip sdwan
- sdwanNode := ipNode.AddChild(&Node{Name: "sdwan", Aliases: []string{"sd-wan"}})
- addPrint(sdwanNode)
- sdwanNode.AddChild(&Node{Name: "status"})
- addRemove(sdwanNode)
- addEnableDisable(sdwanNode)
- sdwanAdd := sdwanNode.AddChild(&Node{Name: "add"})
- sdwanAdd.AddChild(&Node{Name: "name="})
- sdwanAdd.AddChild(&Node{Name: "mode=", Dynamic: func() []string {
- return []string{"weighted", "pcc", "lowest-latency", "lowest-loss", "failover"}
- }})
- sdwanAdd.AddChild(&Node{Name: "auto-nat=", Dynamic: func() []string { return []string{"yes", "no"} }})
- sdwanAdd.AddChild(&Node{Name: "probe-interval="})
- sdwanAdd.AddChild(&Node{Name: "comment="})
- sdwanSet := sdwanNode.AddChild(&Node{Name: "set", Dynamic: dynSDWANGroups})
- sdwanSet.AddChild(&Node{Name: "mode=", Dynamic: func() []string {
- return []string{"weighted", "pcc", "lowest-latency", "lowest-loss", "failover"}
- }})
- sdwanSet.AddChild(&Node{Name: "auto-nat=", Dynamic: func() []string { return []string{"yes", "no"} }})
- sdwanSet.AddChild(&Node{Name: "probe-interval="})
- sdwanSet.AddChild(&Node{Name: "comment="})
- // /ip sdwan member
- sdwanMemNode := sdwanNode.AddChild(&Node{Name: "member", Aliases: []string{"members"}})
- addPrint(sdwanMemNode)
- addRemove(sdwanMemNode)
- addEnableDisable(sdwanMemNode)
- sdwanMemAdd := sdwanMemNode.AddChild(&Node{Name: "add"})
- sdwanMemAdd.AddChild(&Node{Name: "group=", Dynamic: dynSDWANGroups})
- sdwanMemAdd.AddChild(&Node{Name: "interface=", Dynamic: dynInterfaces})
- sdwanMemAdd.AddChild(&Node{Name: "gateway="})
- sdwanMemAdd.AddChild(&Node{Name: "weight="})
- sdwanMemAdd.AddChild(&Node{Name: "priority="})
- sdwanMemAdd.AddChild(&Node{Name: "target-probe="})
- sdwanMemAdd.AddChild(&Node{Name: "max-latency="})
- sdwanMemAdd.AddChild(&Node{Name: "max-loss="})
- sdwanMemAdd.AddChild(&Node{Name: "comment="})
- sdwanMemSet := sdwanMemNode.AddChild(&Node{Name: "set"})
- sdwanMemSet.AddChild(&Node{Name: "group=", Dynamic: dynSDWANGroups})
- sdwanMemSet.AddChild(&Node{Name: "interface=", Dynamic: dynInterfaces})
- sdwanMemSet.AddChild(&Node{Name: "gateway="})
- sdwanMemSet.AddChild(&Node{Name: "weight="})
- sdwanMemSet.AddChild(&Node{Name: "priority="})
- sdwanMemSet.AddChild(&Node{Name: "target-probe="})
- sdwanMemSet.AddChild(&Node{Name: "max-latency="})
- sdwanMemSet.AddChild(&Node{Name: "max-loss="})
- sdwanMemSet.AddChild(&Node{Name: "comment="})
- // Also accessible directly at root /sdwan
- root.AddChild(sdwanNode)
- // 3. /routing
- routingNode := root.AddChild(&Node{Name: "routing"})
- // /routing bgp
- bgpNode := routingNode.AddChild(&Node{Name: "bgp"})
- bgpInst := bgpNode.AddChild(&Node{Name: "instance"})
- addPrint(bgpInst)
- bgpInstSet := bgpInst.AddChild(&Node{Name: "set"})
- bgpInstSet.AddChild(&Node{Name: "as="})
- bgpInstSet.AddChild(&Node{Name: "router-id="})
- bgpInstSet.AddChild(&Node{Name: "enabled=", Dynamic: func() []string { return []string{"yes", "no"} }})
- bgpPeer := bgpNode.AddChild(&Node{Name: "peer", Aliases: []string{"peers", "connection"}})
- addPrint(bgpPeer)
- addRemove(bgpPeer)
- addEnableDisable(bgpPeer)
- bgpPeerAdd := bgpPeer.AddChild(&Node{Name: "add"})
- bgpPeerAdd.AddChild(&Node{Name: "name="})
- bgpPeerAdd.AddChild(&Node{Name: "remote-address="})
- bgpPeerAdd.AddChild(&Node{Name: "remote-as="})
- bgpPeerAdd.AddChild(&Node{Name: "description="})
- bgpNet := bgpNode.AddChild(&Node{Name: "network"})
- addPrint(bgpNet)
- addRemove(bgpNet)
- bgpNetAdd := bgpNet.AddChild(&Node{Name: "add"})
- bgpNetAdd.AddChild(&Node{Name: "network="})
- bgpRoutes := bgpNode.AddChild(&Node{Name: "routes"})
- addPrint(bgpRoutes)
- // /routing ospf
- ospfNode := routingNode.AddChild(&Node{Name: "ospf"})
- ospfInst := ospfNode.AddChild(&Node{Name: "instance", Aliases: []string{"instances"}})
- addPrint(ospfInst)
- addRemove(ospfInst)
- ospfInstAdd := ospfInst.AddChild(&Node{Name: "add"})
- ospfInstAdd.AddChild(&Node{Name: "name="})
- ospfInstAdd.AddChild(&Node{Name: "router-id="})
- ospfInstAdd.AddChild(&Node{Name: "redistribute-connected=", Dynamic: func() []string { return []string{"yes", "no"} }})
- ospfInstAdd.AddChild(&Node{Name: "redistribute-static=", Dynamic: func() []string { return []string{"yes", "no"} }})
- ospfInstAdd.AddChild(&Node{Name: "redistribute-bgp=", Dynamic: func() []string { return []string{"yes", "no"} }})
- ospfInstAdd.AddChild(&Node{Name: "default-metric="})
- ospfInstSet := ospfInst.AddChild(&Node{Name: "set"})
- ospfInstSet.AddChild(&Node{Name: "router-id="})
- ospfInstSet.AddChild(&Node{Name: "redistribute-connected=", Dynamic: func() []string { return []string{"yes", "no"} }})
- ospfInstSet.AddChild(&Node{Name: "redistribute-static=", Dynamic: func() []string { return []string{"yes", "no"} }})
- ospfInstSet.AddChild(&Node{Name: "redistribute-bgp=", Dynamic: func() []string { return []string{"yes", "no"} }})
- ospfInstSet.AddChild(&Node{Name: "default-metric="})
- ospfInstSet.AddChild(&Node{Name: "disabled=", Dynamic: func() []string { return []string{"yes", "no"} }})
- ospfArea := ospfNode.AddChild(&Node{Name: "area", Aliases: []string{"areas"}})
- addPrint(ospfArea)
- addRemove(ospfArea)
- ospfAreaAdd := ospfArea.AddChild(&Node{Name: "add"})
- ospfAreaAdd.AddChild(&Node{Name: "name="})
- ospfAreaAdd.AddChild(&Node{Name: "area-id="})
- ospfAreaAdd.AddChild(&Node{Name: "instance="})
- ospfAreaAdd.AddChild(&Node{Name: "type=", Dynamic: func() []string { return []string{"default", "stub", "nssa"} }})
- ospfAreaAdd.AddChild(&Node{Name: "default-cost="})
- ospfAreaAdd.AddChild(&Node{Name: "no-summaries=", Dynamic: func() []string { return []string{"yes", "no"} }})
- ospfAreaRange := ospfNode.AddChild(&Node{Name: "area-range", Aliases: []string{"range", "ranges"}})
- addPrint(ospfAreaRange)
- addRemove(ospfAreaRange)
- ospfRangeAdd := ospfAreaRange.AddChild(&Node{Name: "add"})
- ospfRangeAdd.AddChild(&Node{Name: "prefix="})
- ospfRangeAdd.AddChild(&Node{Name: "area="})
- ospfRangeAdd.AddChild(&Node{Name: "cost="})
- ospfRangeAdd.AddChild(&Node{Name: "advertise=", Dynamic: func() []string { return []string{"yes", "no"} }})
- ospfIface := ospfNode.AddChild(&Node{Name: "interface", Aliases: []string{"interfaces", "template", "templates"}})
- addPrint(ospfIface)
- addRemove(ospfIface)
- ospfIfaceAdd := ospfIface.AddChild(&Node{Name: "add"})
- ospfIfaceAdd.AddChild(&Node{Name: "interface=", Dynamic: dynInterfaces})
- ospfIfaceAdd.AddChild(&Node{Name: "area="})
- ospfIfaceAdd.AddChild(&Node{Name: "networks="})
- ospfIfaceAdd.AddChild(&Node{Name: "cost="})
- ospfIfaceAdd.AddChild(&Node{Name: "priority="})
- ospfIfaceAdd.AddChild(&Node{Name: "network-type=", Dynamic: func() []string { return []string{"broadcast", "point-to-point", "nonbroadcast", "point-to-multipoint"} }})
- ospfIfaceAdd.AddChild(&Node{Name: "passive=", Dynamic: func() []string { return []string{"yes", "no"} }})
- ospfIfaceAdd.AddChild(&Node{Name: "auth=", Dynamic: func() []string { return []string{"none", "simple", "md5"} }})
- ospfSNbr := ospfNode.AddChild(&Node{Name: "static-neighbor", Aliases: []string{"static-neighbors"}})
- addPrint(ospfSNbr)
- addRemove(ospfSNbr)
- ospfSNbrAdd := ospfSNbr.AddChild(&Node{Name: "add"})
- ospfSNbrAdd.AddChild(&Node{Name: "address="})
- ospfSNbrAdd.AddChild(&Node{Name: "area="})
- ospfSNbrAdd.AddChild(&Node{Name: "poll-interval="})
- ospfSNbrAdd.AddChild(&Node{Name: "cost="})
- ospfNeighbor := ospfNode.AddChild(&Node{Name: "neighbor", Aliases: []string{"neighbors"}})
- addPrint(ospfNeighbor)
- ospfLSA := ospfNode.AddChild(&Node{Name: "lsa", Aliases: []string{"lsadb"}})
- addPrint(ospfLSA)
- ospfRoute := ospfNode.AddChild(&Node{Name: "route", Aliases: []string{"routes"}})
- addPrint(ospfRoute)
- // /routing filter
- routingFilter := routingNode.AddChild(&Node{Name: "filter"})
- addPrint(routingFilter)
- rfRule := routingFilter.AddChild(&Node{Name: "rule", Aliases: []string{"rules"}})
- addPrint(rfRule)
- addRemove(rfRule)
- rfRuleAdd := rfRule.AddChild(&Node{Name: "add"})
- rfRuleAdd.AddChild(&Node{Name: "chain="})
- rfRuleAdd.AddChild(&Node{Name: "action=", Dynamic: func() []string { return []string{"accept", "discard", "reject"} }})
- rfRuleAdd.AddChild(&Node{Name: "prefix="})
- rfRuleAdd.AddChild(&Node{Name: "prefix-len="})
- rfRuleAdd.AddChild(&Node{Name: "rule-order="})
- rfComm := routingFilter.AddChild(&Node{Name: "community-list", Aliases: []string{"community-lists"}})
- addPrint(rfComm)
- addRemove(rfComm)
- rfCommAdd := rfComm.AddChild(&Node{Name: "add"})
- rfCommAdd.AddChild(&Node{Name: "name="})
- rfCommAdd.AddChild(&Node{Name: "communities="})
- rfAS := routingFilter.AddChild(&Node{Name: "as-list", Aliases: []string{"as-lists", "num-list", "num-lists"}})
- addPrint(rfAS)
- addRemove(rfAS)
- rfASAdd := rfAS.AddChild(&Node{Name: "add"})
- rfASAdd.AddChild(&Node{Name: "name="})
- rfASAdd.AddChild(&Node{Name: "range="})
- // /routing rip
- ripNode := routingNode.AddChild(&Node{Name: "rip"})
- ripInst := ripNode.AddChild(&Node{Name: "instance", Aliases: []string{"instances"}})
- addPrint(ripInst)
- addRemove(ripInst)
- addEnableDisable(ripInst)
- ripInstAdd := ripInst.AddChild(&Node{Name: "add"})
- ripInstAdd.AddChild(&Node{Name: "name="})
- ripInstAdd.AddChild(&Node{Name: "version=", Dynamic: func() []string { return []string{"1", "2"} }})
- ripInstAdd.AddChild(&Node{Name: "redistribute-connected=", Dynamic: func() []string { return []string{"yes", "no"} }})
- ripInstAdd.AddChild(&Node{Name: "redistribute-static=", Dynamic: func() []string { return []string{"yes", "no"} }})
- ripInstAdd.AddChild(&Node{Name: "redistribute-ospf=", Dynamic: func() []string { return []string{"yes", "no"} }})
- ripInstAdd.AddChild(&Node{Name: "redistribute-bgp=", Dynamic: func() []string { return []string{"yes", "no"} }})
- ripInstAdd.AddChild(&Node{Name: "redistribute-default=", Dynamic: func() []string { return []string{"yes", "no"} }})
- ripIface := ripNode.AddChild(&Node{Name: "interface", Aliases: []string{"interfaces"}})
- addPrint(ripIface)
- addRemove(ripIface)
- addEnableDisable(ripIface)
- ripIfaceAdd := ripIface.AddChild(&Node{Name: "add"})
- ripIfaceAdd.AddChild(&Node{Name: "interface=", Dynamic: dynInterfaces})
- ripIfaceAdd.AddChild(&Node{Name: "instance="})
- ripIfaceAdd.AddChild(&Node{Name: "metric="})
- ripIfaceAdd.AddChild(&Node{Name: "mode=", Dynamic: func() []string { return []string{"multicast", "broadcast"} }})
- ripIfaceAdd.AddChild(&Node{Name: "passive=", Dynamic: func() []string { return []string{"yes", "no"} }})
- ripIfaceAdd.AddChild(&Node{Name: "use-bfd=", Dynamic: func() []string { return []string{"yes", "no"} }})
- ripNbr := ripNode.AddChild(&Node{Name: "neighbor", Aliases: []string{"neighbors"}})
- addPrint(ripNbr)
- addRemove(ripNbr)
- ripNbrAdd := ripNbr.AddChild(&Node{Name: "add"})
- ripNbrAdd.AddChild(&Node{Name: "address="})
- ripNbrAdd.AddChild(&Node{Name: "instance="})
- ripRoutes := ripNode.AddChild(&Node{Name: "routes", Aliases: []string{"route"}})
- addPrint(ripRoutes)
- // /routing bfd
- bfdNode := routingNode.AddChild(&Node{Name: "bfd"})
- bfdInst := bfdNode.AddChild(&Node{Name: "instance"})
- addPrint(bfdInst)
- bfdInstSet := bfdInst.AddChild(&Node{Name: "set"})
- bfdInstSet.AddChild(&Node{Name: "enabled=", Dynamic: func() []string { return []string{"yes", "no"} }})
- bfdIface := bfdNode.AddChild(&Node{Name: "interface", Aliases: []string{"interfaces"}})
- addPrint(bfdIface)
- addRemove(bfdIface)
- addEnableDisable(bfdIface)
- bfdIfaceAdd := bfdIface.AddChild(&Node{Name: "add"})
- bfdIfaceAdd.AddChild(&Node{Name: "interface=", Dynamic: dynInterfaces})
- bfdIfaceAdd.AddChild(&Node{Name: "min-rx="})
- bfdIfaceAdd.AddChild(&Node{Name: "min-tx="})
- bfdIfaceAdd.AddChild(&Node{Name: "idle-tx="})
- bfdIfaceAdd.AddChild(&Node{Name: "multiplier="})
- bfdIfaceAdd.AddChild(&Node{Name: "passive=", Dynamic: func() []string { return []string{"yes", "no"} }})
- bfdPeer := bfdNode.AddChild(&Node{Name: "peer", Aliases: []string{"peers", "neighbor", "neighbors"}})
- addPrint(bfdPeer)
- addRemove(bfdPeer)
- bfdPeerAdd := bfdPeer.AddChild(&Node{Name: "add"})
- bfdPeerAdd.AddChild(&Node{Name: "address="})
- bfdPeerAdd.AddChild(&Node{Name: "interface=", Dynamic: dynInterfaces})
- bfdPeerAdd.AddChild(&Node{Name: "multihop=", Dynamic: func() []string { return []string{"yes", "no"} }})
- bfdSession := bfdNode.AddChild(&Node{Name: "session", Aliases: []string{"sessions"}})
- addPrint(bfdSession)
- // /routing babel
- babelNode := routingNode.AddChild(&Node{Name: "babel"})
- babelInst := babelNode.AddChild(&Node{Name: "instance", Aliases: []string{"instances"}})
- addPrint(babelInst)
- addRemove(babelInst)
- addEnableDisable(babelInst)
- babelInstAdd := babelInst.AddChild(&Node{Name: "add"})
- babelInstAdd.AddChild(&Node{Name: "name="})
- babelInstAdd.AddChild(&Node{Name: "router-id="})
- babelInstAdd.AddChild(&Node{Name: "redistribute-connected=", Dynamic: func() []string { return []string{"yes", "no"} }})
- babelInstAdd.AddChild(&Node{Name: "redistribute-static=", Dynamic: func() []string { return []string{"yes", "no"} }})
- babelInstAdd.AddChild(&Node{Name: "redistribute-ospf=", Dynamic: func() []string { return []string{"yes", "no"} }})
- babelInstAdd.AddChild(&Node{Name: "redistribute-bgp=", Dynamic: func() []string { return []string{"yes", "no"} }})
- babelIface := babelNode.AddChild(&Node{Name: "interface", Aliases: []string{"interfaces"}})
- addPrint(babelIface)
- addRemove(babelIface)
- addEnableDisable(babelIface)
- babelIfaceAdd := babelIface.AddChild(&Node{Name: "add"})
- babelIfaceAdd.AddChild(&Node{Name: "interface=", Dynamic: dynInterfaces})
- babelIfaceAdd.AddChild(&Node{Name: "instance="})
- babelIfaceAdd.AddChild(&Node{Name: "type=", Dynamic: func() []string { return []string{"wired", "wireless"} }})
- babelIfaceAdd.AddChild(&Node{Name: "rxcost="})
- babelIfaceAdd.AddChild(&Node{Name: "hello-interval="})
- babelIfaceAdd.AddChild(&Node{Name: "update-interval="})
- babelNbr := babelNode.AddChild(&Node{Name: "neighbor", Aliases: []string{"neighbors"}})
- addPrint(babelNbr)
- babelRoutes := babelNode.AddChild(&Node{Name: "routes", Aliases: []string{"route"}})
- addPrint(babelRoutes)
- // /routing radv
- radvNode := routingNode.AddChild(&Node{Name: "radv"})
- radvInst := radvNode.AddChild(&Node{Name: "instance", Aliases: []string{"instances"}})
- addPrint(radvInst)
- addRemove(radvInst)
- addEnableDisable(radvInst)
- radvInstAdd := radvInst.AddChild(&Node{Name: "add"})
- radvInstAdd.AddChild(&Node{Name: "name="})
- radvIface := radvNode.AddChild(&Node{Name: "interface", Aliases: []string{"interfaces"}})
- addPrint(radvIface)
- addRemove(radvIface)
- addEnableDisable(radvIface)
- radvIfaceAdd := radvIface.AddChild(&Node{Name: "add"})
- radvIfaceAdd.AddChild(&Node{Name: "interface=", Dynamic: dynInterfaces})
- radvIfaceAdd.AddChild(&Node{Name: "instance="})
- radvIfaceAdd.AddChild(&Node{Name: "min-ra-interval="})
- radvIfaceAdd.AddChild(&Node{Name: "max-ra-interval="})
- radvIfaceAdd.AddChild(&Node{Name: "default-lifetime="})
- radvIfaceAdd.AddChild(&Node{Name: "prefixes="})
- radvIfaceAdd.AddChild(&Node{Name: "rdnss="})
- // 4. /tool
- toolNode := root.AddChild(&Node{Name: "tool"})
- toolPing := toolNode.AddChild(&Node{Name: "ping"})
- toolPing.AddChild(&Node{Name: "count="})
- toolPing.AddChild(&Node{Name: "size="})
- toolPing.AddChild(&Node{Name: "interval="})
- toolTrace := toolNode.AddChild(&Node{Name: "traceroute"})
- toolTrace.AddChild(&Node{Name: "max-hops="})
- toolBtest := toolNode.AddChild(&Node{Name: "bandwidth-test", Aliases: []string{"btest"}})
- toolBtest.AddChild(&Node{Name: "target="})
- toolBtest.AddChild(&Node{Name: "duration="})
- toolBtest.AddChild(&Node{Name: "direction=", Dynamic: func() []string { return []string{"receive", "send", "both"} }})
- toolNetwatch := toolNode.AddChild(&Node{Name: "netwatch"})
- addPrint(toolNetwatch)
- addRemove(toolNetwatch)
- toolNWAdd := toolNetwatch.AddChild(&Node{Name: "add"})
- toolNWAdd.AddChild(&Node{Name: "host="})
- toolNWAdd.AddChild(&Node{Name: "interval="})
- toolNWAdd.AddChild(&Node{Name: "timeout="})
- toolIPScan := toolNode.AddChild(&Node{Name: "ip-scan"})
- toolIPScan.AddChild(&Node{Name: "interface=", Dynamic: dynInterfaces})
- toolIPScan.AddChild(&Node{Name: "address-range="})
- toolTorch := toolNode.AddChild(&Node{Name: "torch", Aliases: []string{"sniff"}})
- toolTorch.AddChild(&Node{Name: "interface=", Dynamic: dynInterfaces})
- // 5. /log
- logNode := root.AddChild(&Node{Name: "log"})
- logPrint := logNode.AddChild(&Node{Name: "print", Aliases: []string{"pr", "show"}})
- logPrint.AddChild(&Node{Name: "limit="})
- logPrint.AddChild(&Node{Name: "filter="})
- // 6. /user
- userNode := root.AddChild(&Node{Name: "user", Aliases: []string{"users"}})
- addPrint(userNode)
- addRemove(userNode)
- userAdd := userNode.AddChild(&Node{Name: "add"})
- userAdd.AddChild(&Node{Name: "name="})
- userAdd.AddChild(&Node{Name: "password="})
- userAdd.AddChild(&Node{Name: "role=", Dynamic: func() []string { return []string{"admin", "full", "read", "viewer"} }})
- userAdd.AddChild(&Node{Name: "comment="})
- userSet := userNode.AddChild(&Node{Name: "set"})
- userSet.AddChild(&Node{Name: "name="})
- userSet.AddChild(&Node{Name: "password="})
- userSet.AddChild(&Node{Name: "role=", Dynamic: func() []string { return []string{"admin", "full", "read", "viewer"} }})
- userSet.AddChild(&Node{Name: "comment="})
- userSet.AddChild(&Node{Name: "disabled=", Dynamic: func() []string { return []string{"yes", "no"} }})
- // 7. /system
- sysNode := root.AddChild(&Node{Name: "system"})
- sysRes := sysNode.AddChild(&Node{Name: "resource"})
- addPrint(sysRes)
- sysIdent := sysNode.AddChild(&Node{Name: "identity"})
- addPrint(sysIdent)
- sysIdentSet := sysIdent.AddChild(&Node{Name: "set"})
- sysIdentSet.AddChild(&Node{Name: "name="})
- sysPkg := sysNode.AddChild(&Node{Name: "package", Aliases: []string{"upgrade"}})
- addPrint(sysPkg)
- sysPkgUpdate := sysPkg.AddChild(&Node{Name: "update"})
- sysPkgUpdate.AddChild(&Node{Name: "check"})
- sysPkgUpdate.AddChild(&Node{Name: "install"})
- sysNode.AddChild(&Node{Name: "reboot"})
- sysNode.AddChild(&Node{Name: "shutdown", Aliases: []string{"poweroff"}})
- // 8. /certificate
- certNode := root.AddChild(&Node{Name: "certificate", Aliases: []string{"certificates", "cert"}})
- addPrint(certNode)
- certNode.AddChild(&Node{Name: "remove", Aliases: []string{"rem", "delete"}, Dynamic: dynCertificates})
- certNode.AddChild(&Node{Name: "export", Dynamic: dynCertificates})
- certAddCA := certNode.AddChild(&Node{Name: "add-ca"})
- certAddCA.AddChild(&Node{Name: "name="})
- certAddCA.AddChild(&Node{Name: "common-name="})
- certAddCA.AddChild(&Node{Name: "days="})
- certAddCA.AddChild(&Node{Name: "key-type=", Dynamic: func() []string { return []string{"RSA-2048", "RSA-4096", "ECDSA-P256"} }})
- certAdd := certNode.AddChild(&Node{Name: "add"})
- certAdd.AddChild(&Node{Name: "name="})
- certAdd.AddChild(&Node{Name: "common-name="})
- certAdd.AddChild(&Node{Name: "ca=", Dynamic: dynCAs})
- certAdd.AddChild(&Node{Name: "sans="})
- certAdd.AddChild(&Node{Name: "days="})
- certAdd.AddChild(&Node{Name: "key-type=", Dynamic: func() []string { return []string{"RSA-2048", "RSA-4096", "ECDSA-P256"} }})
- certLE := certNode.AddChild(&Node{Name: "issue-letsencrypt"})
- certLE.AddChild(&Node{Name: "domain="})
- certLE.AddChild(&Node{Name: "email="})
- certLE.AddChild(&Node{Name: "name="})
- certLE.AddChild(&Node{Name: "staging=", Dynamic: func() []string { return []string{"yes", "no"} }})
- // 9. Direct root utility commands
- root.AddChild(&Node{Name: "clear"})
- root.AddChild(&Node{Name: "help", Aliases: []string{"?"}})
- root.AddChild(&Node{Name: "quit"})
- root.AddChild(&Node{Name: "exit"})
- root.AddChild(&Node{Name: "ping"})
- root.AddChild(&Node{Name: "traceroute"})
- return root
- }
|