]>
Commit | Line | Data |
---|---|---|
35681c06 | 1 | #!/usr/bin/env python3 |
d486dd0d | 2 | # |
223ba5af | 3 | # Copyright 2014-2019 Cumulus Networks, Inc. All rights reserved. |
d486dd0d JF |
4 | # Authors: |
5 | # Roopa Prabhu, roopa@cumulusnetworks.com | |
6 | # Julien Fortin, julien@cumulusnetworks.com | |
7 | # ifupdown2 -- | |
8 | # tool to configure network interfaces | |
9 | # | |
10 | ||
11 | import os | |
12 | import sys | |
223ba5af | 13 | import logging |
3b01ed76 JF |
14 | import io |
15 | import configparser | |
d486dd0d JF |
16 | |
17 | try: | |
d486dd0d | 18 | from ifupdown2.ifupdown.argv import Parse |
4a888991 | 19 | from ifupdown2.ifupdown.utils import utils |
d486dd0d JF |
20 | from ifupdown2.ifupdown.config import IFUPDOWN2_CONF_PATH |
21 | from ifupdown2.ifupdown.ifupdownmain import ifupdownMain | |
223ba5af JF |
22 | |
23 | from ifupdown2.lib.dry_run import DryRunManager | |
5f6de69f | 24 | from ifupdown2.lib.status import Status |
223ba5af | 25 | |
bd441a51 | 26 | except (ImportError, ModuleNotFoundError): |
d486dd0d | 27 | from ifupdown.argv import Parse |
4a888991 | 28 | from ifupdown.utils import utils |
d486dd0d JF |
29 | from ifupdown.config import IFUPDOWN2_CONF_PATH |
30 | from ifupdown.ifupdownmain import ifupdownMain | |
5f6de69f | 31 | from lib.status import Status |
d486dd0d | 32 | |
223ba5af | 33 | from lib.dry_run import DryRunManager |
d486dd0d | 34 | |
d486dd0d | 35 | |
223ba5af | 36 | log = logging.getLogger() |
d486dd0d | 37 | configmap_g = None |
4a888991 | 38 | lockfile = "/run/network/.lock" |
d486dd0d JF |
39 | |
40 | ||
41 | class Ifupdown2: | |
42 | def __init__(self, daemon, uid): | |
43 | self.daemon = daemon | |
44 | self.uid = uid | |
45 | self.args = None | |
46 | self.op = None | |
47 | ||
48 | self.interfaces_filename = None | |
49 | self.interfaces_file_iobuf = None | |
50 | ||
51 | self.handlers = { | |
52 | 'up': self.run_up, | |
53 | 'down': self.run_down, | |
54 | 'query': self.run_query, | |
55 | 'reload': self.run_reload | |
56 | } | |
57 | ||
58 | def parse_argv(self, argv): | |
59 | args_parse = Parse(argv) | |
60 | args_parse.validate() | |
61 | ||
62 | self.args = args_parse.get_args() | |
63 | self.op = args_parse.get_op() | |
64 | ||
d486dd0d JF |
65 | def main(self, stdin_buffer=None): |
66 | if self.op != 'query' and self.uid != 0: | |
67 | raise Exception('must be root to run this command') | |
68 | ||
69 | try: | |
70 | self.read_config() | |
71 | self.init(stdin_buffer) | |
4a888991 JF |
72 | |
73 | if self.op != 'query' and not utils.lockFile(lockfile): | |
5f6de69f JF |
74 | log.error("Another instance of this program is already running.") |
75 | return Status.Client.STATUS_ALREADY_RUNNING | |
4a888991 | 76 | |
d486dd0d | 77 | self.handlers.get(self.op)(self.args) |
3b01ed76 | 78 | except Exception as e: |
d486dd0d JF |
79 | if not str(e): |
80 | return 1 | |
81 | # if args and args.debug: | |
82 | raise | |
83 | # else: | |
84 | if log: | |
223ba5af | 85 | log.error('main exception: ' + str(e)) |
964e8e5c JF |
86 | #import traceback |
87 | #traceback.print_exc() | |
d486dd0d | 88 | else: |
3b01ed76 | 89 | print(str(e)) |
d486dd0d JF |
90 | # if args and not args.debug: |
91 | # print '\nrerun the command with \'-d\' for a detailed errormsg' | |
92 | return 1 | |
93 | return 0 | |
94 | ||
95 | def init(self, stdin_buffer): | |
223ba5af JF |
96 | ############## |
97 | # dry run mode | |
98 | ############## | |
99 | dry_run_mode_on = DryRunManager.get_instance().is_dry_mode_on() | |
100 | ||
101 | if hasattr(self.args, 'noact'): | |
102 | if self.args.noact and not dry_run_mode_on: | |
103 | DryRunManager.get_instance().dry_run_mode_on() | |
104 | elif not self.args.noact and dry_run_mode_on: | |
105 | DryRunManager.get_instance().dry_run_mode_off() | |
106 | elif dry_run_mode_on: | |
107 | # if noact is not in self.args we are probably in | |
108 | # ifquery mode so we need to turn off dry run mode. | |
109 | DryRunManager.get_instance().dry_run_mode_off() | |
110 | ||
111 | ### | |
112 | ||
d486dd0d JF |
113 | if hasattr(self.args, 'interfacesfile') and self.args.interfacesfile != None: |
114 | # Check to see if -i option is allowed by config file | |
115 | # But for ifquery, we will not check this | |
116 | if (not self.op == 'query' and | |
117 | configmap_g.get('disable_cli_interfacesfile', '0') == '1'): | |
118 | log.error('disable_cli_interfacesfile is set so users ' | |
119 | 'not allowed to specify interfaces file on cli.') | |
120 | raise Exception("") | |
121 | if self.args.interfacesfile == '-': | |
122 | # If interfaces file is stdin, read | |
123 | if self.daemon: | |
124 | self.interfaces_file_iobuf = stdin_buffer | |
125 | else: | |
126 | self.interfaces_file_iobuf = sys.stdin.read() | |
127 | else: | |
128 | self.interfaces_filename = self.args.interfacesfile | |
129 | else: | |
130 | # if the ifupdown2 config file does not have it, default to standard | |
131 | self.interfaces_filename = configmap_g.get('default_interfaces_configfile', | |
132 | '/etc/network/interfaces') | |
133 | ||
134 | def read_config(self): | |
135 | global configmap_g | |
136 | ||
137 | with open(IFUPDOWN2_CONF_PATH, 'r') as f: | |
138 | config = f.read() | |
139 | configStr = '[ifupdown2]\n' + config | |
3b01ed76 JF |
140 | configFP = io.StringIO(configStr) |
141 | parser = configparser.RawConfigParser() | |
d486dd0d JF |
142 | parser.readfp(configFP) |
143 | configmap_g = dict(parser.items('ifupdown2')) | |
144 | ||
145 | # Preprocess config map | |
146 | configval = configmap_g.get('multiple_vlan_aware_bridge_support', '0') | |
147 | if configval == '0': | |
148 | # if multiple bridges not allowed, set the bridge-vlan-aware | |
149 | # attribute in the 'no_repeats' config, so that the ifupdownmain | |
150 | # module can catch it appropriately | |
151 | configmap_g['no_repeats'] = {'bridge-vlan-aware': 'yes'} | |
152 | ||
153 | configval = configmap_g.get('link_master_slave', '0') | |
154 | if configval == '1': | |
155 | # link_master_slave is only valid when all is set | |
156 | if hasattr(self.args, 'all') and not self.args.all: | |
157 | configmap_g['link_master_slave'] = '0' | |
158 | ||
159 | configval = configmap_g.get('delay_admin_state_change', '0') | |
160 | if configval == '1': | |
161 | # reset link_master_slave if delay_admin_state_change is on | |
162 | configmap_g['link_master_slave'] = '0' | |
163 | ||
164 | def run_up(self, args): | |
165 | log.debug('args = %s' % str(args)) | |
166 | ||
167 | try: | |
168 | iflist = args.iflist | |
169 | if len(args.iflist) == 0: | |
170 | iflist = None | |
171 | log.debug('creating ifupdown object ..') | |
172 | cachearg = (False if (iflist or args.nocache or args.noact) | |
173 | else True) | |
9e4c8354 | 174 | ifupdown_handle = ifupdownMain(daemon=self.daemon, args=args, |
d486dd0d JF |
175 | config=configmap_g, |
176 | force=args.force, | |
177 | withdepends=args.withdepends, | |
178 | perfmode=args.perfmode, | |
179 | dryrun=args.noact, | |
180 | cache=cachearg, | |
181 | addons_enable=not args.noaddons, | |
182 | statemanager_enable=not args.noaddons, | |
183 | interfacesfile=self.interfaces_filename, | |
184 | interfacesfileiobuf=self.interfaces_file_iobuf, | |
185 | interfacesfileformat=args.interfacesfileformat) | |
186 | if args.noaddons: | |
187 | ifupdown_handle.up(['up'], args.all, args.CLASS, iflist, | |
188 | excludepats=args.excludepats, | |
189 | printdependency=args.printdependency, | |
190 | syntaxcheck=args.syntaxcheck, type=args.type, | |
191 | skipupperifaces=args.skipupperifaces) | |
192 | else: | |
193 | ifupdown_handle.up(['pre-up', 'up', 'post-up'], | |
194 | args.all, args.CLASS, iflist, | |
195 | excludepats=args.excludepats, | |
196 | printdependency=args.printdependency, | |
197 | syntaxcheck=args.syntaxcheck, type=args.type, | |
198 | skipupperifaces=args.skipupperifaces) | |
199 | except: | |
200 | raise | |
201 | ||
202 | def run_down(self, args): | |
203 | log.debug('args = %s' % str(args)) | |
204 | ||
205 | try: | |
206 | iflist = args.iflist | |
207 | log.debug('creating ifupdown object ..') | |
9e4c8354 | 208 | ifupdown_handle = ifupdownMain(daemon=self.daemon, args=args, |
d486dd0d JF |
209 | config=configmap_g, force=args.force, |
210 | withdepends=args.withdepends, | |
211 | perfmode=args.perfmode, | |
212 | dryrun=args.noact, | |
213 | addons_enable=not args.noaddons, | |
214 | statemanager_enable=not args.noaddons, | |
215 | interfacesfile=self.interfaces_filename, | |
216 | interfacesfileiobuf=self.interfaces_file_iobuf, | |
217 | interfacesfileformat=args.interfacesfileformat) | |
218 | ||
219 | ifupdown_handle.down(['pre-down', 'down', 'post-down'], | |
220 | args.all, args.CLASS, iflist, | |
221 | excludepats=args.excludepats, | |
222 | printdependency=args.printdependency, | |
223 | usecurrentconfig=args.usecurrentconfig, | |
224 | type=args.type) | |
225 | except: | |
226 | raise | |
227 | ||
228 | def run_query(self, args): | |
229 | log.debug('args = %s' % str(args)) | |
230 | ||
231 | try: | |
232 | iflist = args.iflist | |
233 | if args.checkcurr: | |
234 | qop = 'query-checkcurr' | |
235 | elif args.running: | |
236 | qop = 'query-running' | |
237 | elif args.raw: | |
238 | qop = 'query-raw' | |
239 | elif args.syntaxhelp: | |
240 | qop = 'query-syntax' | |
241 | elif args.printdependency: | |
242 | qop = 'query-dependency' | |
243 | elif args.printsavedstate: | |
244 | qop = 'query-savedstate' | |
245 | else: | |
246 | qop = 'query' | |
247 | cachearg = (False if (iflist or args.nocache or args.syntaxhelp or | |
248 | (qop != 'query-checkcurr' and | |
249 | qop != 'query-running')) else True) | |
250 | if not iflist and qop == 'query-running': | |
251 | iflist = [i for i in os.listdir('/sys/class/net/') | |
252 | if os.path.isdir('/sys/class/net/%s' % i)] | |
253 | log.debug('creating ifupdown object ..') | |
9e4c8354 | 254 | ifupdown_handle = ifupdownMain(daemon=self.daemon, args=args, |
d486dd0d JF |
255 | config=configmap_g, |
256 | withdepends=args.withdepends, | |
257 | perfmode=args.perfmode, | |
258 | cache=cachearg, | |
259 | interfacesfile=self.interfaces_filename, | |
260 | interfacesfileiobuf=self.interfaces_file_iobuf, | |
261 | interfacesfileformat=args.interfacesfileformat, | |
262 | withdefaults=args.withdefaults) | |
263 | # list implies all auto interfaces (this is how ifupdown behaves) | |
264 | if args.list: | |
265 | args.all = True | |
266 | ifupdown_handle.query([qop], args.all, args.list, args.CLASS, iflist, | |
267 | excludepats=args.excludepats, | |
268 | printdependency=args.printdependency, | |
269 | format=args.format, type=args.type) | |
270 | except: | |
271 | raise | |
272 | ||
273 | def run_reload(self, args): | |
274 | log.debug('args = %s' % str(args)) | |
275 | ||
276 | try: | |
277 | log.debug('creating ifupdown object ..') | |
9e4c8354 | 278 | ifupdown_handle = ifupdownMain(daemon=self.daemon, args=args, |
d486dd0d JF |
279 | config=configmap_g, |
280 | interfacesfile=self.interfaces_filename, | |
281 | withdepends=args.withdepends, | |
282 | perfmode=args.perfmode, | |
283 | dryrun=args.noact) | |
284 | ifupdown_handle.reload(['pre-up', 'up', 'post-up'], | |
285 | ['pre-down', 'down', 'post-down'], | |
286 | auto=args.all, allow=args.CLASS, ifacenames=None, | |
287 | excludepats=args.excludepats, | |
288 | usecurrentconfig=args.usecurrentconfig, | |
289 | syntaxcheck=args.syntaxcheck, | |
290 | currentlyup=args.currentlyup) | |
291 | except: | |
292 | raise |