mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
Better file parsing routines,
also switch to recreate ldap.conf and krb5.conf from scratch on clients, avoid nasty failures in case the original files contained strange directives
This commit is contained in:
parent
584baa7ee2
commit
566018f4d4
@ -31,6 +31,7 @@ from optparse import OptionParser
|
||||
import ipaclient.ipadiscovery
|
||||
import ipaclient.ipachangeconf
|
||||
from ipa.ipautil import run
|
||||
import shutil
|
||||
|
||||
def parse_options():
|
||||
parser = OptionParser(version=VERSION)
|
||||
@ -123,21 +124,19 @@ def main():
|
||||
|
||||
# Configure ldap.conf
|
||||
ldapconf = ipaclient.ipachangeconf.IPAChangeConf("IPA Installer")
|
||||
opts = [{'name':'host', 'action':'comment'},
|
||||
{'name':'port', 'action':'comment'},
|
||||
{'name':'binddn', 'action':'comment'},
|
||||
{'name':'bindpw', 'action':'comment'},
|
||||
{'name':'rootbinddn', 'action':'comment'},
|
||||
{'name':'nss_base_passwd', 'value':ds.getBaseDN()+'?sub', 'action':'set'},
|
||||
{'name':'nss_base_group', 'value':ds.getBaseDN()+'?sub', 'action':'set'},
|
||||
{'name':'base', 'value':ds.getBaseDN(), 'action':'set'},
|
||||
{'name':'ldap_version', 'value':'3', 'action':'set'}]
|
||||
if dnsok and not options.force:
|
||||
opts.insert(0, {'name':'uri', 'action':'comment'})
|
||||
else:
|
||||
opts.append({'name':'uri', 'value':'ldap://'+ds.getServerName(), 'action':'set'})
|
||||
ldapconf.setOptionAssignment(" ")
|
||||
ldapconf.changeConf("/etc/ldap.conf", opts)
|
||||
|
||||
opts = [{'name':'comment', 'type':'comment', 'value':'File modified by ipa-client-install'},
|
||||
{'name':'empty', 'type':'empty'},
|
||||
{'name':'nss_base_passwd', 'type':'option', 'value':ds.getBaseDN()+'?sub'},
|
||||
{'name':'nss_base_group', 'type':'option', 'value':ds.getBaseDN()+'?sub'},
|
||||
{'name':'base', 'type':'option', 'value':ds.getBaseDN()},
|
||||
{'name':'ldap_version', 'type':'option', 'value':'3'}]
|
||||
if not dnsok or options.force:
|
||||
opts.append({'name':'uri', 'type':'option', 'value':'ldap://'+ds.getServerName()})
|
||||
|
||||
opts.append({'name':'empty', 'type':'empty'})
|
||||
ldapconf.newConf("/etc/ldap.conf", opts)
|
||||
|
||||
#Check if kerberos is already configured properly
|
||||
krbctx = krbV.default_context()
|
||||
@ -149,33 +148,52 @@ def main():
|
||||
krbconf = ipaclient.ipachangeconf.IPAChangeConf("IPA Installer")
|
||||
krbconf.setOptionAssignment(" = ")
|
||||
krbconf.setSectionNameDelimiters(("[","]"))
|
||||
krbconf.setSubSectionDelimiters(("{","}"))
|
||||
krbconf.setIndent((""," "," "))
|
||||
|
||||
opts = [{'name':'comment', 'type':'comment', 'value':'File modified by ipa-client-install'},
|
||||
{'name':'empty', 'type':'empty'}]
|
||||
|
||||
#[libdefaults]
|
||||
opts = [{'name':'default_realm', 'value':ds.getRealmName(), 'action':'set'},
|
||||
{'name':'ticket_lifetime', 'value':'24h', 'action':'set'},
|
||||
{'name':'forwardable', 'value':'yes', 'action':'set'}]
|
||||
libopts = [{'name':'default_realm', 'type':'option', 'value':ds.getRealmName()}]
|
||||
if dnsok and not options.force:
|
||||
opts.insert(1, {'name':'dns_lookup_realm', 'value':'true', 'action':'set'})
|
||||
opts.insert(2, {'name':'dns_lookup_kdc', 'value':'true', 'action':'set'})
|
||||
libopts.append({'name':'dns_lookup_realm', 'type':'option', 'value':'true'})
|
||||
libopts.append({'name':'dns_lookup_kdc', 'type':'option', 'value':'true'})
|
||||
else:
|
||||
opts.insert(1, {'name':'dns_lookup_realm', 'value':'false', 'action':'set'})
|
||||
opts.insert(2, {'name':'dns_lookup_kdc', 'value':'false', 'action':'set'})
|
||||
krbconf.changeConf("/etc/krb5.conf", opts, "libdefaults");
|
||||
libopts.append({'name':'dns_lookup_realm', 'type':'option', 'value':'false'})
|
||||
libopts.append({'name':'dns_lookup_kdc', 'type':'option', 'value':'false'})
|
||||
libopts.append({'name':'ticket_lifetime', 'type':'option', 'value':'24h'})
|
||||
libopts.append({'name':'forwardable', 'type':'option', 'value':'yes'})
|
||||
|
||||
opts.append({'name':'libdefaults', 'type':'section', 'value':libopts})
|
||||
opts.append({'name':'empty', 'type':'empty'})
|
||||
|
||||
#the following are necessary only if DNS discovery does not work
|
||||
if not dnsok or options.force:
|
||||
#[realms]
|
||||
opts = [{'name':ds.getRealmName(), 'value':'{', 'action':'set'},
|
||||
{'name':'kdc', 'value':ds.getServerName()+':88', 'action':'set'},
|
||||
{'name':'admin_server', 'value':ds.getServerName()+':749', 'action':'set'},
|
||||
# adding '\n}' is a dirty hack because we still don't have subsections support
|
||||
{'name':'default_domain', 'value':ds.getDomainName()+'\n}', 'action':'set'}]
|
||||
krbconf.changeConf("/etc/krb5.conf", opts, "realms");
|
||||
kropts =[{'name':'kdc', 'type':'option', 'value':ds.getServerName()+':88'},
|
||||
{'name':'admin_server', 'type':'option', 'value':ds.getServerName()+':749'},
|
||||
{'name':'default_domain', 'type':'option', 'value':ds.getDomainName()}]
|
||||
ropts = [{'name':ds.getRealmName(), 'type':'subsection', 'value':kropts}]
|
||||
opts.append({'name':'realms', 'type':'section', 'value':ropts})
|
||||
opts.append({'name':'empty', 'type':'empty'})
|
||||
|
||||
#[domain_realm]
|
||||
opts = [{'name':'.'+ds.getDomainName(), 'value':ds.getRealmName(), 'action':'set'},
|
||||
{'name':ds.getDomainName(), 'value':ds.getRealmName(), 'action':'set'}]
|
||||
krbconf.changeConf("/etc/krb5.conf", opts, "domain_realm");
|
||||
dropts = [{'name':'.'+ds.getDomainName(), 'type':'option', 'value':ds.getRealmName()},
|
||||
{'name':ds.getDomainName(), 'type':'option', 'value':ds.getRealmName()}]
|
||||
opts.append({'name':'domain_realm', 'type':'section', 'value':dropts})
|
||||
opts.append({'name':'empty', 'type':'empty'})
|
||||
|
||||
#[appdefaults]
|
||||
pamopts = [{'name':'debug', 'type':'option', 'value':'false'},
|
||||
{'name':'ticket_lifetime', 'type':'option', 'value':'36000'},
|
||||
{'name':'renew_lifetime', 'type':'option', 'value':'36000'},
|
||||
{'name':'forwardable', 'type':'option', 'value':'true'},
|
||||
{'name':'krb4_convert', 'type':'option', 'value':'false'}]
|
||||
appopts = [{'name':'pam', 'type':'subsection', 'value':pamopts}]
|
||||
opts.append({'name':'appdefaults', 'type':'section', 'value':appopts})
|
||||
|
||||
krbconf.newConf("/etc/krb5.conf", opts);
|
||||
|
||||
#Modify nsswitch to add nss_ldap
|
||||
run(["/usr/sbin/authconfig", "--enableldap", "--update"])
|
||||
|
@ -23,21 +23,22 @@ import fcntl
|
||||
import os
|
||||
import string
|
||||
import time
|
||||
import shutil
|
||||
|
||||
def openLocked(filename, perms):
|
||||
fd = -1
|
||||
try:
|
||||
fd = os.open(filename, os.O_RDWR | os.O_CREAT, perms)
|
||||
|
||||
fcntl.lockf(fd, fcntl.LOCK_EX)
|
||||
except OSError, (errno, strerr):
|
||||
if fd != -1:
|
||||
try:
|
||||
os.close(fd)
|
||||
except OSError:
|
||||
pass
|
||||
raise IOError(errno, strerr)
|
||||
return os.fdopen(fd, "r+")
|
||||
fd = -1
|
||||
try:
|
||||
fd = os.open(filename, os.O_RDWR | os.O_CREAT, perms)
|
||||
|
||||
fcntl.lockf(fd, fcntl.LOCK_EX)
|
||||
except OSError, (errno, strerr):
|
||||
if fd != -1:
|
||||
try:
|
||||
os.close(fd)
|
||||
except OSError:
|
||||
pass
|
||||
raise IOError(errno, strerr)
|
||||
return os.fdopen(fd, "r+")
|
||||
|
||||
|
||||
#TODO: add subsection as a concept
|
||||
@ -49,44 +50,43 @@ class IPAChangeConf:
|
||||
|
||||
def __init__(self, name):
|
||||
self.progname = name
|
||||
self.optpre = ("",)
|
||||
self.doptpre = self.optpre[0]
|
||||
self.assign = (" = ",)
|
||||
self.indent = ("","","")
|
||||
self.assign = (" = ","=")
|
||||
self.dassign = self.assign[0]
|
||||
self.comment = ("#",)
|
||||
self.dcomment = self.comment[0]
|
||||
self.eol = ("\n",)
|
||||
self.deol = self.eol[0]
|
||||
#self.sectnamdel = ("[","]")
|
||||
self.sectnamdel = ()
|
||||
self.newsection = False
|
||||
self.sectnamdel = ("[","]")
|
||||
self.subsectdel = ("{","}")
|
||||
|
||||
def setProgName(self, name):
|
||||
self.progname = name
|
||||
|
||||
def setOptionPrefix(self, prefix):
|
||||
if type(prefix) is list:
|
||||
self.optpre = prefix
|
||||
def setIndent(self, indent):
|
||||
if type(indent) is tuple:
|
||||
self.indent = indent
|
||||
elif type(indent) is str:
|
||||
self.indent = (indent, )
|
||||
else:
|
||||
self.optpre = (prefix, )
|
||||
self.doptpre = self.optpre[0]
|
||||
raise ValueError, 'Indent must be a list of strings'
|
||||
|
||||
def setOptionAssignment(self, assign):
|
||||
if type(assign) is list:
|
||||
if type(assign) is tuple:
|
||||
self.assign = assign
|
||||
else:
|
||||
self.assign = (assign, )
|
||||
self.dassign = self.assign[0]
|
||||
|
||||
def setCommentPrefix(self, comment):
|
||||
if type(comment) is list:
|
||||
if type(comment) is tuple:
|
||||
self.comment = comment
|
||||
else:
|
||||
self.comment = (comment, )
|
||||
self.dcomment = self.comment[0]
|
||||
|
||||
def setEndLine(self, eol):
|
||||
if type(eol) is list:
|
||||
if type(eol) is tuple:
|
||||
self.eol = eol
|
||||
else:
|
||||
self.eol = (eol, )
|
||||
@ -95,56 +95,19 @@ class IPAChangeConf:
|
||||
def setSectionNameDelimiters(self, delims):
|
||||
self.sectnamdel = delims
|
||||
|
||||
def confDump(self, options):
|
||||
output = ""
|
||||
|
||||
#pre conf options delimiter
|
||||
output += self.deol
|
||||
output += self.dcomment+"["+self.progname+"]--start-line--"+self.deol
|
||||
output += self.dcomment+" Generated by authconfig on " + time.strftime("%Y/%m/%d %H:%M:%S") + self.deol
|
||||
output += self.dcomment+" DO NOT EDIT THIS SECTION (delimited by --start-line--/--end-line--)"+self.deol
|
||||
output += self.dcomment+" Any modification may be deleted or altered by authconfig in future"+self.deol
|
||||
output += self.deol
|
||||
|
||||
if self.newsection:
|
||||
output += getSectionLine(section)
|
||||
|
||||
#set options
|
||||
for opt in options:
|
||||
if opt['action'] == "set":
|
||||
output += self.doptpre+opt['name']+self.dassign+opt['value']+self.deol
|
||||
|
||||
#post conf options delimiter
|
||||
output += self.deol
|
||||
output += self.dcomment+"["+self.progname+"]--end-line--"+self.deol
|
||||
output += self.deol
|
||||
|
||||
return output
|
||||
|
||||
def matchAutoEnd(self, line):
|
||||
if line.endswith("]--end-line--"):
|
||||
return True
|
||||
return False
|
||||
|
||||
def matchAutoStart(self, line):
|
||||
if line.endswith("]--start-line--"):
|
||||
return True
|
||||
return False
|
||||
def setSubSectionDelimiters(self, delims):
|
||||
self.subsectdel = delims
|
||||
|
||||
def matchComment(self, line):
|
||||
for v in self.comment:
|
||||
if line.strip().startswith(v):
|
||||
return True
|
||||
if line.lstrip().startswith(v):
|
||||
return line.lstrip()[len(v):]
|
||||
return False
|
||||
|
||||
def matchLineOption(self, line, opt):
|
||||
parts = line.split(self.dassign, 1)
|
||||
if len(parts) < 2:
|
||||
return False
|
||||
elif parts[0].split() == opt['name'].split():
|
||||
def matchEmpty(self, line):
|
||||
if line.strip() == "":
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
return False
|
||||
|
||||
def matchSection(self, line):
|
||||
cl = "".join(line.strip().split()).lower()
|
||||
@ -156,84 +119,297 @@ class IPAChangeConf:
|
||||
return False
|
||||
return cl[len(self.sectnamdel[0]):-len(self.sectnamdel[1])]
|
||||
|
||||
def matchSubSection(self, line):
|
||||
if self.matchComment(line):
|
||||
return False
|
||||
|
||||
parts = line.split(self.dassign, 1)
|
||||
if len(parts) < 2:
|
||||
return False
|
||||
|
||||
if parts[1].strip() == self.subsectdel[0]:
|
||||
return parts[0].strip()
|
||||
|
||||
return False
|
||||
|
||||
def matchSubSectionEnd(self, line):
|
||||
if self.matchComment(line):
|
||||
return False
|
||||
|
||||
if line.strip() == self.subsectdel[1]:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def getSectionLine(self, section):
|
||||
if len(self.sectnamdel) != 2:
|
||||
return section
|
||||
return self.sectnamdel[0]+section+self.sectnamdel[1]+self.deol
|
||||
|
||||
def checkLineOption(self, line, options):
|
||||
def dump(self, options, level=0):
|
||||
output = ""
|
||||
if level >= len(self.indent):
|
||||
level = len(self.indent)-1
|
||||
|
||||
# Check if this is a setting we care about.
|
||||
for opt in options:
|
||||
if self.matchLineOption(line.strip(), opt):
|
||||
output = self.dcomment
|
||||
break
|
||||
for o in options:
|
||||
if o['type'] == "section":
|
||||
output += self.sectnamdel[0]+o['name']+self.sectnamdel[1]+self.deol
|
||||
output += self.dump(o['value'], level+1)
|
||||
continue
|
||||
if o['type'] == "subsection":
|
||||
output += self.indent[level]+o['name']+self.dassign+self.subsectdel[0]+self.deol
|
||||
output += self.dump(o['value'], level+1)
|
||||
output += self.indent[level]+self.subsectdel[1]+self.deol
|
||||
continue
|
||||
if o['type'] == "option":
|
||||
output += self.indent[level]+o['name']+self.dassign+o['value']+self.deol
|
||||
continue
|
||||
if o['type'] == "comment":
|
||||
output += self.dcomment+o['value']+self.deol
|
||||
continue
|
||||
if o['type'] == "empty":
|
||||
output += self.deol
|
||||
continue
|
||||
raise SyntaxError, 'Unknown type: ['+o['type']+']'
|
||||
|
||||
output += line
|
||||
return output;
|
||||
return output
|
||||
|
||||
def parseLine(self, line):
|
||||
|
||||
if self.matchEmpty(line):
|
||||
return {'name':'empty', 'type':'empty'}
|
||||
|
||||
value = self.matchComment(line)
|
||||
if value:
|
||||
return {'name':'comment', 'type':'comment', 'value':value.rstrip()}
|
||||
|
||||
parts = line.split(self.dassign, 1)
|
||||
if len(parts) < 2:
|
||||
raise SyntaxError, 'Syntax Error: Unknown line format'
|
||||
|
||||
return {'name':parts[0].strip(), 'type':'option', 'value':parts[1].rstrip()}
|
||||
|
||||
def findOpts(self, opts, type, name, exclude_sections=False):
|
||||
|
||||
num = 0
|
||||
for o in opts:
|
||||
if o['type'] == type and o['name'] == name:
|
||||
return (num, o)
|
||||
if exclude_sections and (o['type'] == "section" or o['type'] == "subsection"):
|
||||
return (num, None)
|
||||
num += 1
|
||||
return (num, None)
|
||||
|
||||
def commentOpts(self, inopts, level = 0):
|
||||
|
||||
opts = []
|
||||
|
||||
if level >= len(self.indent):
|
||||
level = len(self.indent)-1
|
||||
|
||||
for o in inopts:
|
||||
if o['type'] == 'section':
|
||||
no = self.commentOpts(o['value'], level+1)
|
||||
val = self.dcomment+self.sectnamdel[0]+o['name']+self.sectnamdel[1]
|
||||
opts.append({'name':'comment', 'type':'comment', 'value':val})
|
||||
for n in no:
|
||||
opts.append(n)
|
||||
continue
|
||||
if o['type'] == 'subsection':
|
||||
no = self.commentOpts(o['value'], level+1)
|
||||
val = self.indent[level]+o['name']+self.dassign+self.subsectdel[0]
|
||||
opts.append({'name':'comment', 'type':'comment', 'value':val})
|
||||
for n in no:
|
||||
opts.append(n)
|
||||
val = self.indent[level]+self.subsectdel[1]
|
||||
opts.append({'name':'comment', 'type':'comment', 'value':val})
|
||||
continue
|
||||
if o['type'] == 'option':
|
||||
val = self.indent[level]+o['name']+self.dassign+o['value']
|
||||
opts.append({'name':'comment', 'type':'comment', 'value':val})
|
||||
continue
|
||||
if o['type'] == 'comment':
|
||||
opts.append(o)
|
||||
continue
|
||||
if o['type'] == 'empty':
|
||||
opts.append({'name':'comment', 'type':'comment', 'value':''})
|
||||
continue
|
||||
raise SyntaxError, 'Unknown type: ['+o['type']+']'
|
||||
|
||||
return opts
|
||||
|
||||
def mergeOld(self, oldopts, newopts):
|
||||
|
||||
opts = []
|
||||
|
||||
for o in oldopts:
|
||||
if o['type'] == "section" or o['type'] == "subsection":
|
||||
(num, no) = self.findOpts(newopts, o['type'], o['name'])
|
||||
if not no:
|
||||
opts.append(o)
|
||||
continue
|
||||
if no['action'] == "set":
|
||||
mo = self.mergeOld(o['value'], no['value'])
|
||||
opts.append({'name':o['name'], 'type':o['type'], 'value':mo})
|
||||
continue
|
||||
if no['action'] == "comment":
|
||||
co = self.commentOpts(o['value'])
|
||||
for c in co:
|
||||
opts.append(c)
|
||||
continue
|
||||
if no['action'] == "remove":
|
||||
continue
|
||||
raise SyntaxError, 'Unknown action: ['+no['action']+']'
|
||||
|
||||
if o['type'] == "comment" or o['type'] == "empty":
|
||||
opts.append(o)
|
||||
continue
|
||||
|
||||
if o['type'] == "option":
|
||||
(num, no) = self.findOpts(newopts, 'option', o['name'], True)
|
||||
if not no:
|
||||
opts.append(o)
|
||||
continue
|
||||
if no['action'] == 'comment' or no['action'] == 'remove':
|
||||
if no['value'] != None and o['value'] != no['value']:
|
||||
opts.append(o)
|
||||
continue
|
||||
if no['action'] == 'comment':
|
||||
opts.append({'name':'comment', 'type':'comment',
|
||||
'value':self.dcomment+o['name']+self.dassign+o['value']})
|
||||
continue
|
||||
if no['action'] == 'set':
|
||||
opts.append(no)
|
||||
continue
|
||||
raise SyntaxError, 'Unknown action: ['+o['action']+']'
|
||||
|
||||
raise SyntaxError, 'Unknown type: ['+o['type']+']'
|
||||
|
||||
return opts
|
||||
|
||||
def mergeNew(self, opts, newopts):
|
||||
|
||||
cline = 0
|
||||
|
||||
for no in newopts:
|
||||
|
||||
if no['type'] == "section" or no['type'] == "subsection":
|
||||
(num, o) = self.findOpts(opts, no['type'], no['name'])
|
||||
if not o:
|
||||
if no['action'] == 'set':
|
||||
opts.append(no)
|
||||
continue
|
||||
if no['action'] == "set":
|
||||
self.mergeNew(o['value'], no['value'])
|
||||
continue
|
||||
cline = num+1
|
||||
continue
|
||||
|
||||
if no['type'] == "option":
|
||||
(num, o) = self.findOpts(opts, no['type'], no['name'], True)
|
||||
if not o:
|
||||
if no['action'] == 'set':
|
||||
opts.append(no)
|
||||
continue
|
||||
cline = num+1
|
||||
continue
|
||||
|
||||
if no['type'] == "comment" or no['type'] == "empty":
|
||||
opts.insert(cline, no)
|
||||
cline += 1
|
||||
continue
|
||||
|
||||
raise SyntaxError, 'Unknown type: ['+no['type']+']'
|
||||
|
||||
|
||||
def merge(self, oldopts, newopts):
|
||||
|
||||
#Use a two pass strategy
|
||||
#First we create a new opts tree from oldopts removing/commenting
|
||||
# the options as indicated by the contents of newopts
|
||||
#Second we fill in the new opts tree with options as indicated
|
||||
# in the newopts tree (this is becaus eentire (sub)sections may
|
||||
# exist in the newopts that do not exist in oldopts)
|
||||
|
||||
opts = self.mergeOld(oldopts, newopts)
|
||||
self.mergeNew(opts, newopts)
|
||||
return opts
|
||||
|
||||
#TODO: Make parse() recursive?
|
||||
def parse(self, f):
|
||||
|
||||
opts = []
|
||||
sectopts = []
|
||||
section = None
|
||||
subsectopts = []
|
||||
subsection = None
|
||||
curopts = opts
|
||||
fatheropts = opts
|
||||
|
||||
# Read in the old file.
|
||||
for line in f:
|
||||
|
||||
# It's a section start.
|
||||
value = self.matchSection(line)
|
||||
if value:
|
||||
if section is not None:
|
||||
opts.append({'name':section, 'type':'section', 'value':sectopts})
|
||||
sectopts = []
|
||||
curopts = sectopts
|
||||
fatheropts = sectopts
|
||||
section = value
|
||||
continue
|
||||
|
||||
# It's a subsection start.
|
||||
value = self.matchSubSection(line)
|
||||
if value:
|
||||
if subsection is not None:
|
||||
raise SyntaxError, 'nested subsections are not supported yet'
|
||||
subsectopts = []
|
||||
curopts = subsectopts
|
||||
subsection = value
|
||||
continue
|
||||
|
||||
value = self.matchSubSectionEnd(line)
|
||||
if value:
|
||||
if subsection is None:
|
||||
raise SyntaxError, 'Unmatched end subsection terminator found'
|
||||
fatheropts.append({'name':subsection, 'type':'subsection', 'value':subsectopts})
|
||||
subsection = None
|
||||
curopts = fatheropts
|
||||
continue
|
||||
|
||||
# Copy anything else as is.
|
||||
curopts.append(self.parseLine(line))
|
||||
|
||||
#Add last section if any
|
||||
if len(sectopts) is not 0:
|
||||
opts.append({'name':section, 'type':'section', 'value':sectopts})
|
||||
|
||||
return opts
|
||||
|
||||
# Write settings to configuration file
|
||||
# file is a path
|
||||
# options is a set of dictionaries in the form:
|
||||
# [{'name': 'foo', 'value': 'bar', 'action': 'set/comment'}]
|
||||
# section is a section name like 'global'
|
||||
def changeConf(self, file, options, section=None):
|
||||
def changeConf(self, file, newopts):
|
||||
autosection = False
|
||||
savedsection = None
|
||||
savedsection = None
|
||||
done = False
|
||||
output = ""
|
||||
f = None
|
||||
try:
|
||||
#Do not catch an unexisting file error, we want to fail in that case
|
||||
shutil.copy2(file, file+".ipabkp")
|
||||
|
||||
f = openLocked(file, 0644)
|
||||
|
||||
# Read in the old file.
|
||||
for line in f:
|
||||
oldopts = self.parse(f)
|
||||
|
||||
if autosection:
|
||||
if self.matchAutoEnd(line):
|
||||
autosection = False
|
||||
#skip all previous auto-generated lines
|
||||
continue
|
||||
options = self.merge(oldopts, newopts)
|
||||
|
||||
if self.matchAutoStart(line):
|
||||
autosection = True
|
||||
continue
|
||||
|
||||
# If it's a comment, just pass it through.
|
||||
if self.matchComment(line):
|
||||
output += line
|
||||
continue
|
||||
|
||||
# If it's a section start, note the section name.
|
||||
value = self.matchSection(line)
|
||||
if value:
|
||||
|
||||
# Here we are at start if a new section, if the previous one matches
|
||||
# the specified section, dump here before starting the new one
|
||||
# the comparison with section == None is intentional and matches the
|
||||
# request to dump the options at the end of an implicit initial
|
||||
# unmarked section before any section is started
|
||||
if savedsection == section:
|
||||
output += self.confDump(options)
|
||||
done = True
|
||||
|
||||
savedsection = value
|
||||
output += line
|
||||
continue
|
||||
|
||||
# Comment out options we care about.
|
||||
if savedsection == section:
|
||||
output += self.checkLineOption(line, options)
|
||||
continue
|
||||
|
||||
# Copy anything else as is.
|
||||
output += line
|
||||
|
||||
if not done:
|
||||
if section:
|
||||
self.newsection = True
|
||||
output += self.confDump(options)
|
||||
output = self.dump(options)
|
||||
|
||||
# Write it out and close it.
|
||||
f.seek(0)
|
||||
@ -246,3 +422,39 @@ class IPAChangeConf:
|
||||
except IOError:
|
||||
pass
|
||||
return True
|
||||
|
||||
# Write settings to new file, backup old
|
||||
# file is a path
|
||||
# options is a set of dictionaries in the form:
|
||||
# [{'name': 'foo', 'value': 'bar', 'action': 'set/comment'}]
|
||||
# section is a section name like 'global'
|
||||
def newConf(self, file, options):
|
||||
autosection = False
|
||||
savedsection = None
|
||||
done = False
|
||||
output = ""
|
||||
f = None
|
||||
try:
|
||||
try:
|
||||
shutil.copy2(file, file+".ipabkp")
|
||||
except IOError, err:
|
||||
if err.errno == 2:
|
||||
# The orign file did not exist
|
||||
pass
|
||||
|
||||
f = openLocked(file, 0644)
|
||||
|
||||
# Trunkate
|
||||
f.seek(0)
|
||||
f.truncate(0)
|
||||
|
||||
output = self.dump(options)
|
||||
|
||||
f.write(output)
|
||||
finally:
|
||||
try:
|
||||
if f:
|
||||
f.close()
|
||||
except IOError:
|
||||
pass
|
||||
return True
|
||||
|
Loading…
Reference in New Issue
Block a user