I am trying to change static
to dhcp
in the /etc/network/interfaces
file and vice versa using Python.
def setMode(mode,port,interfaces):
#If the port's mode is not configured in the interface file, add a line for it, and return
if "iface "+port+" inet " not in interfaces:
newLine="\niface "+port+" inet "+mode
interfaces="".join([interfaces,newLine])
return interfaces
#split the string by port to get to the line containing the port's ip mode
#then split the third element of the resulting list by newline to isolate the end of that line
split1=interfaces.partition(port+" inet ")
split2=split1[2].partition("\n")
#split the isolated line by space to get each word in it. the last element in the resulting list will be the current ip mode
line=split2[0].split(" ")
#if the current mode matches the new mode, return
if line[len(line)-1] == mode:
line=" ".join(line)
split2="".join([line,split2[1],split2[2]])
interfaces="".join([split1[0],split1[1],split2])
return interfaces
#otherwise set the last element to the new mode
line[len(line)-1]=mode
#join the line and lines back to recreate the full string
line=" ".join(line)
split2="".join([line,split2[1],split2[2]])
interfaces="".join([split1[0],split1[1],split2])
return interfaces
This is the code I am taking over with. I am using str.partition()
to achieve this. mode == static
or dhcp
, port = eth8
or eth0
, etc, interfaces
= copy of interfaces file.
/etc/network/interfaces
looks like this:
auto lo iface lo inet loopback auto eth8 iface eth8 inet static address 10.8.100.36 netmask 255.255.0.0 gateway 10.8.1.1
2 Answers 2
The splitting / partitioning makes this very complicated and hard to follow. Instead of splitting and then putting the pieces back together, it would be vastly simpler to replace with a regex, for example:
import re
def set_mode(mode, iface, interfaces):
"""
Set the mode for the specified interface
:param mode: 'dhcp' or 'static'
:param iface: name of the interface, for example eth1, eth2, ...
:param interfaces: content of /etc/network/interfaces
:return: updated content, to be saved in /etc/network/interfaces
"""
iface_prefix = 'iface {} inet '.format(iface)
iface_entry = iface_prefix + mode
if iface_prefix in interfaces:
interfaces = re.sub(iface_prefix + r'.*', iface_entry, interfaces)
else:
interfaces += '\n' + iface_entry
return interfaces
For your sample file, the following gives me the same output with the original method and this new one:
with open('./interfaces') as fh:
content = fh.read()
print set_mode('static', 'eth8', content)
print '---'
print set_mode('dhcp', 'eth8', content)
print '---'
print set_mode('dhcp', 'eth1', content)
Coding style
The original code has several issues that violate PEP8, the official coding style guide of Python:
- Use
snake_case
for function and variable names (that's why I renamedsetMode
toset_mode
- Put spaces around operators:
a=something
instead ofa = something
- A docstring is strongly recommended for the
set_mode
function
-
\$\begingroup\$ This makes much more sense to me then the partition code that there was. Hopefully I can take this style and expand it to the rest of the document I am working on. I have just started working in python and have already been given a challenging task and dead line. \$\endgroup\$Keith– Keith2014年09月10日 12:02:38 +00:00Commented Sep 10, 2014 at 12:02
-
\$\begingroup\$ I also did notice the
.format(iface)
. From my experiences I have seen the%s
later to be followed up by%iface
. Is one method better or just a preference? \$\endgroup\$Keith– Keith2014年09月10日 12:05:17 +00:00Commented Sep 10, 2014 at 12:05 -
\$\begingroup\$ I don't know if
.format(...)
is preferred over... % ...
style, or the other way around. I see more and more experienced Python programmers (on this site) prefer.format(...)
, but I don't have proper evidence or authoritative source. \$\endgroup\$janos– janos2014年09月10日 12:14:41 +00:00Commented Sep 10, 2014 at 12:14 -
\$\begingroup\$ Does the
r'.*'
just mean anything else on the line? \$\endgroup\$Keith– Keith2014年09月10日 12:34:13 +00:00Commented Sep 10, 2014 at 12:34 -
\$\begingroup\$ It means "0 or more of any character": it should match everything until the end of the line. \$\endgroup\$janos– janos2014年09月10日 12:37:03 +00:00Commented Sep 10, 2014 at 12:37
Interface
I see several problems with def setMode(mode,port,interfaces)
:
- In the
interfaces(5)
man page, what you call the "mode" is called "method", and the "port" is called "interface". To reduce confusion, avoid inventing non-standard terminology. PEP 8 says:
Function Names
Function names should be lowercase, with words separated by underscores as necessary to improve readability.
mixedCase is allowed only in contexts where that's already the prevailing style (e.g. threading.py), to retain backwards compatibility.
I propose changing the function signature to def set_method(config, iface, method)
.
I've also chosen to reverse the parameters to make more sense to me: start with an existing configuration, find the relevant interface, and set its method.
Strategy
That's a lot of code to accomplish a somewhat simple task. It's also fragile: an extra space in, say, iface eth0 inet dhcp
could throw it off.
Fundamentally, the whole problem is just a fancy string substitution: replace a string that looks like iface iface inet method
, or append such a line to the end if no such interface is found. Fancy string substitutions are best done using regular expressions.
import re
def set_method(config, iface, method):
return re.sub(r'\n?iface[ ]+%s[ ]+inet(.*)|\Z' % (re.escape(iface)),
'\niface %s inet %s' % (iface, method),
config,
count=1)
Basically, that says, find a string that looks like iface iface inet anything else on the line
, optionally preceded by a Newline, and with words separated by at least one space. If no such line is found, then operate on the end of the string instead. Replace whatever was found with the desired line.
-
\$\begingroup\$ Thank You, what you are saying makes a lot of sense. Splitting up the string and putting it back together makes it challenging. I took over this code and am just starting to get into python. It is a fun language but a lot of tricks. To me it seems as if there are going to be a lot of problems with this code I was given. I spent most of my day yesterday attempting to figure out how to output to the terminal window when the script is ran so I can debug. I know data is being transmitted via Json but I have no idea how that works with python. I have a lot of catching up to do with no time. \$\endgroup\$Keith– Keith2014年09月10日 11:55:33 +00:00Commented Sep 10, 2014 at 11:55
-
\$\begingroup\$ Sadly I was unable to figure out how to output segments of code for debugging purposes. \$\endgroup\$Keith– Keith2014年09月10日 11:56:41 +00:00Commented Sep 10, 2014 at 11:56
newLine
section at the end of the/etc/network/interfaces
but have yet to get it to be able to changestatic
todhcp
. I am not too confident if thepartitioning
is being done right. \$\endgroup\$