41
41
# of the older style colon interfaces for IP aliasing. So we have to use
42
42
# a hack to get IP aliasing working:
43
43
# https://bbs.archlinux.org/viewtopic.php?pid=951573#p951573
45
# Arch is a rolling release, meaning new features and updated packages
46
# roll out on a unpredictable schedule. It also means there is no such
47
# thing as v1.0 or v2.0. We check if the netcfg package is installed to
48
# determine which format should be used.
58
63
def _execute(command):
64
logging.info('executing %s' % ' '.join(command))
59
66
pipe = subprocess.PIPE
60
logging.info('executing %s' % ' '.join(command))
61
67
p = subprocess.Popen(command, stdin=pipe, stdout=pipe, stderr=pipe, env={})
62
logging.debug('waiting on pid %d' % p.pid)
63
status = os.waitpid(p.pid, 0)[1]
64
logging.debug('status = %d' % status)
69
# Wait for process to finish and get output
70
stdout, stderr = p.communicate()
72
logging.debug('status = %d' % p.returncode)
74
logging.info('stdout = %r' % stdout)
75
logging.info('stderr = %r' % stderr)
69
80
def configure_network(hostname, interfaces):
70
# Arch is a rolling release, meaning new features and updated packages
71
# roll out on a unpredictable schedule. It also means there is no such
72
# thing as v1.0 or v2.0. So, let's try checking if the netcfg package
73
# is installed to see what format should be used.
83
# We need to figure out what style of network configuration is
84
# currently being used by looking at /etc/rc.conf and then look
85
# to see what style of network configuration we want to use by
86
# looking to see if the netcfg package is installed
88
if os.path.exists(CONF_FILE):
89
update_files[CONF_FILE] = open(CONF_FILE).read()
91
infile = StringIO(update_files.get(CONF_FILE, ''))
93
cur_netcfg = True # Currently using netcfg
94
lines, variables = _parse_config(infile)
95
lineno = variables.get('DAEMONS')
96
if lineno is not None:
97
daemons = _parse_variable(lines[lineno])
98
if 'network' in daemons:
99
# Config uses legacy style networking
74
102
status = _execute(['/usr/bin/pacman', '-Q', 'netcfg'])
75
103
use_netcfg = (status == 0)
76
104
logging.info('using %s style configuration' %
77
105
(use_netcfg and 'netcfg' or 'legacy'))
81
if os.path.exists(CONF_FILE):
82
update_files[CONF_FILE] = open(CONF_FILE).read()
85
108
remove_files, netnames = process_interface_files_netcfg(
86
109
update_files, interfaces)
145
168
for netname in netnames:
146
169
status = _execute(['/usr/bin/netcfg', '-u', netname])
148
logging.info(' %s, failed (status %d)' % (netname, status))
171
logging.info(' %s, failed (status %d), trying again' %
174
# HACK: Migrating from legacy to netcfg configurations is
175
# troublesome because of Arch bugs. Stopping the network
176
# in legacy downs the interface, but doesn't remove the IP
177
# addresses. This causes netcfg to complain and fail when
178
# we go to configure the interface up. As a side-effect, it
179
# will remove the offending IP. A second attempt to configure
180
# the interface up succeeds. So we'll try a second time.
181
status = _execute(['/usr/bin/netcfg', '-u', netname])
183
logging.info(' %s, failed (status %d)' %
187
logging.info(' %s, success' % netname)
151
189
logging.info(' %s, success' % netname)
198
236
return [name.lstrip('!') for name in re.split('\s+', v.strip())]
239
def _parse_config(infile):
246
# FIXME: This doesn't correctly parse shell scripts perfectly. It
247
# assumes a fairly simple subset
252
k, v = line.split('=', 1)
254
variables[k] = len(lines) - 1
256
return lines, variables
201
259
def _update_rc_conf_legacy(infile, interfaces):
203
261
Return data for (sub-)interfaces and routes
256
314
routes.append(('gateway6', 'default gw %s' % gateway6))
258
316
# Then load old file
265
# FIXME: This doesn't correctly parse shell scripts perfectly. It
266
# assumes a fairly simple subset
271
k, v = line.split('=', 1)
273
variables[k] = len(lines) - 1
317
lines, variables = _parse_config(infile)
275
319
# Update INTERFACES
276
320
lineno = variables.get('INTERFACES')
415
459
def _update_rc_conf_netcfg(infile, netnames):
423
# FIXME: This doesn't correctly parse shell scripts perfectly. It
424
# assumes a fairly simple subset
429
k, v = line.split('=', 1)
431
variables[k] = len(lines) - 1
461
lines, variables = _parse_config(infile)
433
463
# Update NETWORKS
434
464
lineno = variables.get('NETWORKS')