/
vlans_cli.go
196 lines (160 loc) · 4.83 KB
/
vlans_cli.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
// Copyright (2015) Sandia Corporation.
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// the U.S. Government retains certain rights in this software.
package main
import (
"errors"
"minicli"
log "minilog"
"path/filepath"
"strconv"
"strings"
"vlans"
)
var VLANs = vlans.NewVLANs()
var vlansCLIHandlers = []minicli.Handler{
{ // vlans
HelpShort: "display allocated VLANs",
HelpLong: `
Display information about allocated VLANs. With no arguments, prints out the
known VLAN aliases. The following subcommands are supported:
range - view or set the VLAN range
add - add an alias
blacklist - view or create blacklisted VLAN
Note: this command is namespace aware so, for example, adding a range applies
to all *new* VLAN aliases in the current namespace.`,
Patterns: []string{
"vlans",
"vlans <range,>",
"vlans <range,> <min> <max>",
"vlans <add,> <alias> <vlan>",
"vlans <blacklist,> [vlan]",
},
Call: wrapSimpleCLI(cliVLANs),
},
{ // clear vlans
HelpShort: "clear allocated VLANs",
HelpLong: `
Clear one or more aliases, freeing the VLANs for reuse. You should only clear
allocated VLANs once you have killed all the VMs connected to them.
By default, "clear vlans" only clears aliases for the current namespace. If
given "all" as the prefix, all state about managed VLANs is cleared across
*all* namespaces, including blacklisted VLANS. You should only use this if you
want a completely clean slate.`,
Patterns: []string{
"clear vlans [prefix]",
},
Call: wrapSimpleCLI(cliClearVLANs),
},
}
var vlansCLISubHandlers = map[string]wrappedCLIFunc{
"add": cliVLANsAdd,
"range": cliVLANsRange,
"blacklist": cliVLANsBlacklist,
}
func cliVLANs(ns *Namespace, c *minicli.Command, resp *minicli.Response) error {
// Look for matching subhandler
if len(c.BoolArgs) > 0 {
for k, fn := range vlansCLISubHandlers {
if c.BoolArgs[k] {
log.Debug("vlan handler %v", k)
return fn(ns, c, resp)
}
}
}
// No match, must want to just print
resp.Header = []string{"alias", "vlan"}
resp.Tabular = vlans.Tabular(ns.Name)
return nil
}
func cliVLANsAdd(ns *Namespace, c *minicli.Command, resp *minicli.Response) error {
alias := c.StringArgs["alias"]
vlan, err := strconv.Atoi(c.StringArgs["vlan"])
if err != nil {
return errors.New("expected integer VLAN")
}
err = vlans.AddAlias(ns.Name, alias, vlan)
if err == nil {
// update file so that we have a copy of the vlans if minimega crashes
mustWrite(filepath.Join(*f_base, "vlans"), vlanInfo())
}
return err
}
func cliVLANsRange(ns *Namespace, c *minicli.Command, resp *minicli.Response) error {
// ranges are special if we're in the default namespace -- a range gets set
// globally for all namespaces.
name := ns.Name
if name == DefaultNamespace {
name = ""
}
if c.StringArgs["min"] != "" && c.StringArgs["max"] != "" {
min, err := strconv.Atoi(c.StringArgs["min"])
max, err2 := strconv.Atoi(c.StringArgs["max"])
if err != nil || err2 != nil {
return errors.New("expected integer values for min/max")
} else if max <= min {
return errors.New("expected min > max")
}
return vlans.SetRange(name, min, max)
}
// Must want to display the ranges
resp.Header = []string{"min", "max", "next"}
resp.Tabular = [][]string{}
for prefix, r := range vlans.GetRanges() {
if name != prefix {
continue
}
resp.Tabular = append(resp.Tabular,
[]string{
strconv.Itoa(r.Min),
strconv.Itoa(r.Max),
strconv.Itoa(r.Next),
})
}
return nil
}
func cliVLANsBlacklist(ns *Namespace, c *minicli.Command, resp *minicli.Response) error {
if v := c.StringArgs["vlan"]; v != "" {
vlan, err := strconv.Atoi(v)
if err != nil {
return errors.New("expected integer VLAN")
}
vlans.Blacklist(vlan)
return nil
}
// Must want to display the blacklisted VLANs
resp.Header = []string{"vlan"}
resp.Tabular = [][]string{}
for _, v := range vlans.GetBlacklist() {
resp.Tabular = append(resp.Tabular,
[]string{
strconv.Itoa(v),
})
}
return nil
}
func cliClearVLANs(ns *Namespace, c *minicli.Command, resp *minicli.Response) error {
prefix := c.StringArgs["prefix"]
if prefix == Wildcard {
log.Info("resetting VLAN state")
vlans.Default = vlans.NewVLANs()
return nil
}
vlans.Delete(ns.Name, prefix)
mustWrite(filepath.Join(*f_base, "vlans"), vlanInfo())
return nil
}
// cliVLANSuggest returns a list of VLAN suggestions for tab completion.
// Performs a bit of extra work to make sure that the suggestions are in the
// current namespace (completes across namespaces if prefix includes
// vlans.AliasSep).
func cliVLANSuggest(ns *Namespace, prefix string) []string {
if !strings.Contains(prefix, vlans.AliasSep) {
prefix = ns.Name + vlans.AliasSep + prefix
}
res := vlans.GetAliases(ns.Name)
for i, v := range res {
res[i] = strings.TrimPrefix(v, ns.Name+vlans.AliasSep)
}
return res
}