]>
Commit | Line | Data |
---|---|---|
d486dd0d JF |
1 | #!/usr/bin/python |
2 | # | |
3 | # Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved. | |
4 | # Authors: | |
5 | # Roopa Prabhu, roopa@cumulusnetworks.com | |
6 | # Julien Fortin, julien@cumulusnetworks.com | |
7 | # | |
8 | ||
9 | import sys | |
10 | import argparse | |
11 | import argcomplete | |
12 | ||
13 | try: | |
14 | from ifupdown2.ifupdown.utils import utils | |
15 | from ifupdown2.ifupdown.exceptions import ArgvParseError | |
16 | except: | |
17 | from ifupdown.utils import utils | |
18 | from ifupdown.exceptions import ArgvParseError | |
19 | ||
20 | ||
21 | class VersionAction(argparse.Action): | |
22 | def __call__(self, parser, namespace, values, option_string=None): | |
23 | ||
24 | try: | |
25 | dpkg = utils.exec_commandl([utils.dpkg_cmd, '-l', 'ifupdown2']) | |
26 | ||
27 | if not dpkg: | |
28 | raise Exception('dpkg -l ifupdown2 returns without output') | |
29 | ||
30 | dpkg = dpkg.split('\n') | |
31 | ||
32 | if not dpkg: | |
33 | raise Exception('dpkg -l ifupdown2 returns without output') | |
34 | ||
35 | for line in dpkg: | |
36 | if 'ifupdown2' in line: | |
37 | info = line.split() | |
38 | ||
39 | sys.stdout.write('ifupdown2:%s\n' % (info[2])) | |
40 | sys.exit(0) | |
41 | ||
42 | raise Exception('ifupdown2 package not found using dpkg -l') | |
43 | ||
44 | except Exception as e: | |
45 | sys.stderr.write('error: cannot get current version using dpkg: %s\n' % str(e)) | |
46 | sys.exit(1) | |
47 | ||
48 | ||
49 | class Parse: | |
50 | valid_ops = { | |
51 | 'ifup': 'up', | |
52 | 'ifdown': 'down', | |
53 | 'ifreload': 'reload', | |
54 | 'ifquery': 'query' | |
55 | } | |
56 | ||
57 | def __init__(self, argv): | |
58 | self.executable_name = argv[0] | |
59 | self.op = self.get_op() | |
60 | self.argv = argv[1:] | |
61 | ||
62 | if self.op == 'query': | |
63 | descr = 'query interfaces (all or interface list)' | |
64 | elif self.op == 'reload': | |
65 | descr = 'reload interface configuration.' | |
66 | else: | |
67 | descr = 'interface management' | |
68 | argparser = argparse.ArgumentParser(description=descr) | |
69 | if self.op == 'reload': | |
70 | self.update_ifreload_argparser(argparser) | |
71 | else: | |
72 | self.update_argparser(argparser) | |
73 | if self.op == 'up': | |
74 | self.update_ifup_argparser(argparser) | |
75 | elif self.op == 'down': | |
76 | self.update_ifdown_argparser(argparser) | |
77 | elif self.op == 'query': | |
78 | self.update_ifquery_argparser(argparser) | |
79 | self.update_common_argparser(argparser) | |
80 | argcomplete.autocomplete(argparser) | |
81 | self.args = argparser.parse_args(self.argv) | |
82 | ||
83 | def validate(self): | |
84 | if self.op == 'query' and (self.args.syntaxhelp or self.args.list): | |
85 | return True | |
86 | ||
87 | if self.op == 'reload': | |
88 | if not self.args.all and not self.args.currentlyup and not self.args.CLASS: | |
89 | raise ArgvParseError("'-a' or '-c' or '-allow' option is required") | |
90 | elif not self.args.iflist and not self.args.all and not self.args.CLASS: | |
91 | raise ArgvParseError("'-a' option or interface list are required") | |
92 | ||
93 | if self.args.iflist and self.args.all: | |
94 | raise ArgvParseError("'-a' option and interface list are mutually exclusive") | |
95 | ||
96 | if self.op != 'reload' and self.args.CLASS and self.args.all: | |
97 | raise ArgvParseError("'--allow' option is mutually exclusive with '-a'") | |
98 | return True | |
99 | ||
100 | def get_op(self): | |
101 | try: | |
102 | for key, value in self.valid_ops.iteritems(): | |
103 | if self.executable_name.endswith(key): | |
104 | return value | |
105 | except: | |
106 | raise ArgvParseError("Unexpected executable. Should be 'ifup' or 'ifdown' or 'ifquery'") | |
107 | ||
108 | def get_args(self): | |
109 | return self.args | |
110 | ||
111 | def update_argparser(self, argparser): | |
112 | """ base parser, common to all commands """ | |
113 | argparser.add_argument('-a', '--all', action='store_true', required=False, | |
114 | help='process all interfaces marked "auto"') | |
115 | argparser.add_argument('iflist', metavar='IFACE', nargs='*', | |
116 | help='interface list separated by spaces. ' | |
117 | 'IFACE list is mutually exclusive with -a option.') | |
118 | argparser.add_argument('-v', '--verbose', dest='verbose', action='store_true', help='verbose') | |
119 | argparser.add_argument('-d', '--debug', dest='debug', action='store_true', help='output debug info') | |
120 | argparser.add_argument('-q', '--quiet', dest='quiet', action='store_true', help=argparse.SUPPRESS) | |
121 | argparser.add_argument('--allow', dest='CLASS', action='append', help='ignore non-"allow-CLASS" interfaces') | |
122 | argparser.add_argument('-w', '--with-depends', dest='withdepends', action='store_true', | |
123 | help="run with all dependent interfaces. " | |
124 | "This option is redundant when '-a' is specified. " | |
125 | "With '-a' interfaces are always executed in dependency order") | |
126 | argparser.add_argument('--perfmode', dest='perfmode', action='store_true', help=argparse.SUPPRESS) | |
127 | argparser.add_argument('--nocache', dest='nocache', action='store_true', help=argparse.SUPPRESS) | |
128 | argparser.add_argument('-X', '--exclude', dest='excludepats', action='append', | |
129 | help='Exclude interfaces from the list of interfaces to operate on. ' | |
130 | 'Can be specified multiple times.') | |
131 | argparser.add_argument('-i', '--interfaces', dest='interfacesfile', default=None, | |
132 | help='Specify interfaces file instead of file defined in ifupdown2.conf file') | |
133 | argparser.add_argument('-t', '--interfaces-format', dest='interfacesfileformat', default='native', | |
134 | choices=['native', 'json'], help='interfaces file format') | |
135 | argparser.add_argument('-T', '--type', dest='type', default=None, choices=['iface', 'vlan'], | |
136 | help='type of interface entry (iface or vlan). ' | |
137 | 'This option can be used in case of ambiguity between ' | |
138 | 'a vlan interface and an iface interface of the same name') | |
139 | ||
140 | def update_ifupdown_argparser(self, argparser): | |
141 | """ common arg parser for ifup and ifdown """ | |
142 | argparser.add_argument('-f', '--force', dest='force', action='store_true', help='force run all operations') | |
143 | argparser.add_argument('-l', '--syslog', dest='syslog', action='store_true', help=argparse.SUPPRESS) | |
144 | group = argparser.add_mutually_exclusive_group(required=False) | |
145 | group.add_argument('-n', '--no-act', dest='noact', action='store_true', | |
146 | help="print out what would happen, but don't do it") | |
147 | group.add_argument('-p', '--print-dependency', dest='printdependency', | |
148 | choices=['list', 'dot'], help='print iface dependency') | |
149 | group.add_argument('--no-scripts', '--admin-state', dest='noaddons', action='store_true', | |
150 | help='dont run any addon modules/scripts. Only bring the interface administratively up/down') | |
151 | ||
152 | def update_ifup_argparser(self, argparser): | |
153 | argparser.add_argument('-s', '--syntax-check', dest='syntaxcheck', | |
154 | action='store_true', help='Only run the interfaces file parser') | |
155 | argparser.add_argument('-k', '--skip-upperifaces', dest='skipupperifaces', action='store_true', | |
156 | help='ifup by default tries to add newly created interfaces into its upper/parent ' | |
157 | 'interfaces. Eg. if a bridge port is created as a result of ifup on the port, ' | |
158 | 'ifup automatically adds the port to the bridge. This option can be used to ' | |
159 | 'disable this default behaviour') | |
160 | self.update_ifupdown_argparser(argparser) | |
161 | ||
162 | def update_ifdown_argparser(self, argparser): | |
163 | self.update_ifupdown_argparser(argparser) | |
164 | argparser.add_argument('-u', '--use-current-config', | |
165 | dest='usecurrentconfig', action='store_true', | |
166 | help='By default ifdown looks at the saved state for interfaces to bring down. ' | |
167 | 'This option allows ifdown to look at the current interfaces file. ' | |
168 | 'Useful when your state file is corrupted or you want down to use ' | |
169 | 'the latest from the interfaces file') | |
170 | ||
171 | def update_ifquery_argparser(self, argparser): | |
172 | """ arg parser for ifquery options """ | |
173 | ||
174 | # -l is same as '-a', only here for backward compatibility | |
175 | argparser.add_argument('-l', '--list', action='store_true', dest='list', | |
176 | help='list all matching known interfaces') | |
177 | group = argparser.add_mutually_exclusive_group(required=False) | |
178 | group.add_argument('-r', '--running', dest='running', action='store_true', | |
179 | help='query running state of an interface') | |
180 | group.add_argument('-c', '--check', dest='checkcurr', action='store_true', | |
181 | help='check interface file contents against running state of an interface') | |
182 | group.add_argument('-x', '--raw', action='store_true', dest='raw', help='print raw config file entries') | |
183 | group.add_argument('--print-savedstate', action='store_true', dest='printsavedstate', help=argparse.SUPPRESS) | |
184 | argparser.add_argument('-o', '--format', dest='format', default='native', | |
185 | choices=['native', 'json'], help='interface display format') | |
186 | argparser.add_argument('-p', '--print-dependency', dest='printdependency', | |
187 | choices=['list', 'dot'], help='print interface dependency') | |
188 | argparser.add_argument('-s', '--syntax-help', action='store_true', dest='syntaxhelp', | |
189 | help='print supported interface config syntax') | |
190 | argparser.add_argument('--with-defaults', action='store_true', dest='withdefaults', | |
191 | help='check policy default file contents, for unconfigured attributes, ' | |
192 | 'against running state of an interface') | |
193 | ||
194 | def update_ifreload_argparser(self, argparser): | |
195 | """ parser for ifreload """ | |
196 | group = argparser.add_mutually_exclusive_group(required=True) | |
197 | group.add_argument('-a', '--all', action='store_true', help='process all interfaces marked "auto"') | |
198 | group.add_argument('-c', '--currently-up', dest='currentlyup', action='store_true', | |
199 | help='Reload the configuration for all interfaces which are ' | |
200 | 'currently up regardless of whether an interface has ' | |
201 | '"auto <interface>" configuration within the /etc/network/interfaces file.') | |
202 | group.add_argument('--allow', dest='CLASS', action='append', help='ignore non-"allow-CLASS" interfaces') | |
203 | argparser.add_argument('iflist', metavar='IFACE', nargs='*', help=argparse.SUPPRESS) | |
204 | argparser.add_argument('-n', '--no-act', dest='noact', action='store_true', | |
205 | help='print out what would happen, but don\'t do it') | |
206 | argparser.add_argument('-v', '--verbose', dest='verbose', action='store_true', help='verbose') | |
207 | argparser.add_argument('-d', '--debug', dest='debug', action='store_true', help='output debug info') | |
208 | argparser.add_argument('-w', '--with-depends', dest='withdepends', action='store_true', help=argparse.SUPPRESS) | |
209 | argparser.add_argument('--perfmode', dest='perfmode', action='store_true', help=argparse.SUPPRESS) | |
210 | argparser.add_argument('--nocache', dest='nocache', action='store_true', help=argparse.SUPPRESS) | |
211 | argparser.add_argument('-X', '--exclude', dest='excludepats', action='append', help=argparse.SUPPRESS) | |
212 | # argparser.add_argument('-j', '--jobs', dest='jobs', type=int, | |
213 | # default=-1, choices=range(1,12), help=argparse.SUPPRESS) | |
214 | # argparser.add_argument('-i', '--interfaces', dest='interfacesfile', | |
215 | # default='/etc/network/interfaces', | |
216 | # help='use interfaces file instead of default ' + | |
217 | # '/etc/network/interfaces') | |
218 | argparser.add_argument('-u', '--use-current-config', dest='usecurrentconfig', action='store_true', | |
219 | help='By default ifreload looks at saved state for interfaces to bring down. ' | |
220 | 'With this option ifreload will only look at the current interfaces file. ' | |
221 | 'Useful when your state file is corrupted or you want down to use the latest ' | |
222 | 'from the interfaces file') | |
223 | argparser.add_argument('-l', '--syslog', dest='syslog', action='store_true', help=argparse.SUPPRESS) | |
224 | argparser.add_argument('-f', '--force', dest='force', action='store_true', help='force run all operations') | |
225 | argparser.add_argument('-s', '--syntax-check', dest='syntaxcheck', action='store_true', | |
226 | help='Only run the interfaces file parser') | |
227 | ||
228 | def update_common_argparser(self, argparser): | |
229 | ''' general parsing rules ''' | |
230 | ||
231 | argparser.add_argument('-V', '--version', action=VersionAction, nargs=0) |