mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
Move ipachangeconf from ipaclient.install to ipapython
This will let us call it from ipaplatform. Mark the original location as deprecated. Reviewed-By: Francois Cami <fcami@redhat.com> Reviewed-By: Rob Crittenden <rcritten@redhat.com>
This commit is contained in:
parent
b27ad6e9f9
commit
e5af8c19a9
@ -22,7 +22,7 @@ from __future__ import print_function
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
import ipaclient.install.ipachangeconf
|
from ipapython import ipachangeconf
|
||||||
from ipapython.config import IPAOptionParser
|
from ipapython.config import IPAOptionParser
|
||||||
from ipapython.dn import DN
|
from ipapython.dn import DN
|
||||||
from ipapython import version
|
from ipapython import version
|
||||||
@ -229,7 +229,7 @@ def sigterm_handler(signum, frame):
|
|||||||
|
|
||||||
def configure_krb5_conf(realm, kdc, filename):
|
def configure_krb5_conf(realm, kdc, filename):
|
||||||
|
|
||||||
krbconf = ipaclient.install.ipachangeconf.IPAChangeConf("IPA Installer")
|
krbconf = ipachangeconf.IPAChangeConf("IPA Installer")
|
||||||
krbconf.setOptionAssignment((" = ", " "))
|
krbconf.setOptionAssignment((" = ", " "))
|
||||||
krbconf.setSectionNameDelimiters(("[","]"))
|
krbconf.setSectionNameDelimiters(("[","]"))
|
||||||
krbconf.setSubSectionDelimiters(("{","}"))
|
krbconf.setSubSectionDelimiters(("{","}"))
|
||||||
|
@ -18,566 +18,18 @@
|
|||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
|
|
||||||
import fcntl
|
import warnings
|
||||||
import logging
|
from ipapython.ipachangeconf import IPAChangeConf as realIPAChangeConf
|
||||||
import os
|
|
||||||
import shutil
|
|
||||||
|
|
||||||
import six
|
|
||||||
|
|
||||||
if six.PY3:
|
|
||||||
unicode = str
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
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 as e:
|
|
||||||
if fd != -1:
|
|
||||||
try:
|
|
||||||
os.close(fd)
|
|
||||||
except OSError:
|
|
||||||
pass
|
|
||||||
raise IOError(e.errno, e.strerror)
|
|
||||||
return os.fdopen(fd, "r+")
|
|
||||||
|
|
||||||
|
|
||||||
#TODO: add subsection as a concept
|
class IPAChangeConf(realIPAChangeConf):
|
||||||
# (ex. REALM.NAME = { foo = x bar = y } )
|
"""Advertise the old name"""
|
||||||
#TODO: put section delimiters as separating element of the list
|
|
||||||
# so that we can process multiple sections in one go
|
|
||||||
#TODO: add a comment all but provided options as a section option
|
|
||||||
class IPAChangeConf:
|
|
||||||
def __init__(self, name):
|
def __init__(self, name):
|
||||||
self.progname = name
|
"""something"""
|
||||||
self.indent = ("", "", "")
|
warnings.warn(
|
||||||
self.assign = (" = ", "=")
|
"Use 'ipapython.ipachangeconf.IPAChangeConfg'",
|
||||||
self.dassign = self.assign[0]
|
DeprecationWarning,
|
||||||
self.comment = ("#",)
|
stacklevel=2
|
||||||
self.dcomment = self.comment[0]
|
)
|
||||||
self.eol = ("\n",)
|
super(IPAChangeConf, self).__init__(name)
|
||||||
self.deol = self.eol[0]
|
|
||||||
self.sectnamdel = ("[", "]")
|
|
||||||
self.subsectdel = ("{", "}")
|
|
||||||
self.case_insensitive_sections = True
|
|
||||||
|
|
||||||
def setProgName(self, name):
|
|
||||||
self.progname = name
|
|
||||||
|
|
||||||
def setIndent(self, indent):
|
|
||||||
if type(indent) is tuple:
|
|
||||||
self.indent = indent
|
|
||||||
elif type(indent) is str:
|
|
||||||
self.indent = (indent, )
|
|
||||||
else:
|
|
||||||
raise ValueError('Indent must be a list of strings')
|
|
||||||
|
|
||||||
def setOptionAssignment(self, assign):
|
|
||||||
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 tuple:
|
|
||||||
self.comment = comment
|
|
||||||
else:
|
|
||||||
self.comment = (comment, )
|
|
||||||
self.dcomment = self.comment[0]
|
|
||||||
|
|
||||||
def setEndLine(self, eol):
|
|
||||||
if type(eol) is tuple:
|
|
||||||
self.eol = eol
|
|
||||||
else:
|
|
||||||
self.eol = (eol, )
|
|
||||||
self.deol = self.eol[0]
|
|
||||||
|
|
||||||
def setSectionNameDelimiters(self, delims):
|
|
||||||
self.sectnamdel = delims
|
|
||||||
|
|
||||||
def setSubSectionDelimiters(self, delims):
|
|
||||||
self.subsectdel = delims
|
|
||||||
|
|
||||||
def matchComment(self, line):
|
|
||||||
for v in self.comment:
|
|
||||||
if line.lstrip().startswith(v):
|
|
||||||
return line.lstrip()[len(v):]
|
|
||||||
return False
|
|
||||||
|
|
||||||
def matchEmpty(self, line):
|
|
||||||
if line.strip() == "":
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def matchSection(self, line):
|
|
||||||
cl = "".join(line.strip().split())
|
|
||||||
cl = cl.lower() if self.case_insensitive_sections else cl
|
|
||||||
|
|
||||||
if len(self.sectnamdel) != 2:
|
|
||||||
return False
|
|
||||||
if not cl.startswith(self.sectnamdel[0]):
|
|
||||||
return False
|
|
||||||
if not cl.endswith(self.sectnamdel[1]):
|
|
||||||
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._dump_line(self.sectnamdel[0],
|
|
||||||
section,
|
|
||||||
self.sectnamdel[1],
|
|
||||||
self.deol)
|
|
||||||
|
|
||||||
def _dump_line(self, *args):
|
|
||||||
return u"".join(unicode(x) for x in args)
|
|
||||||
|
|
||||||
def dump(self, options, level=0):
|
|
||||||
output = []
|
|
||||||
if level >= len(self.indent):
|
|
||||||
level = len(self.indent) - 1
|
|
||||||
|
|
||||||
for o in options:
|
|
||||||
if o['type'] == "section":
|
|
||||||
output.append(self._dump_line(self.sectnamdel[0],
|
|
||||||
o['name'],
|
|
||||||
self.sectnamdel[1]))
|
|
||||||
output.append(self.dump(o['value'], (level + 1)))
|
|
||||||
continue
|
|
||||||
if o['type'] == "subsection":
|
|
||||||
output.append(self._dump_line(self.indent[level],
|
|
||||||
o['name'],
|
|
||||||
self.dassign,
|
|
||||||
self.subsectdel[0]))
|
|
||||||
output.append(self.dump(o['value'], (level + 1)))
|
|
||||||
output.append(self._dump_line(self.indent[level],
|
|
||||||
self.subsectdel[1]))
|
|
||||||
continue
|
|
||||||
if o['type'] == "option":
|
|
||||||
delim = o.get('delim', self.dassign)
|
|
||||||
if delim not in self.assign:
|
|
||||||
raise ValueError('Unknown delim "%s" must be one of "%s"' % (delim, " ".join([d for d in self.assign])))
|
|
||||||
output.append(self._dump_line(self.indent[level],
|
|
||||||
o['name'],
|
|
||||||
delim,
|
|
||||||
o['value']))
|
|
||||||
continue
|
|
||||||
if o['type'] == "comment":
|
|
||||||
output.append(self._dump_line(self.dcomment, o['value']))
|
|
||||||
continue
|
|
||||||
if o['type'] == "empty":
|
|
||||||
output.append('')
|
|
||||||
continue
|
|
||||||
raise SyntaxError('Unknown type: [%s]' % o['type'])
|
|
||||||
|
|
||||||
# append an empty string to the output so that we add eol to the end
|
|
||||||
# of the file contents in a single join()
|
|
||||||
output.append('')
|
|
||||||
return self.deol.join(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()} # pylint: disable=E1103
|
|
||||||
|
|
||||||
o = dict()
|
|
||||||
parts = line.split(self.dassign, 1)
|
|
||||||
if len(parts) < 2:
|
|
||||||
# The default assign didn't match, try the non-default
|
|
||||||
for d in self.assign[1:]:
|
|
||||||
parts = line.split(d, 1)
|
|
||||||
if len(parts) >= 2:
|
|
||||||
o['delim'] = d
|
|
||||||
break
|
|
||||||
|
|
||||||
if 'delim' not in o:
|
|
||||||
raise SyntaxError('Syntax Error: Unknown line format')
|
|
||||||
|
|
||||||
o.update({'name':parts[0].strip(), 'type':'option', 'value':parts[1].rstrip()})
|
|
||||||
return o
|
|
||||||
|
|
||||||
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._dump_line(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._dump_line(self.indent[level],
|
|
||||||
o['name'],
|
|
||||||
self.dassign,
|
|
||||||
self.subsectdel[0])
|
|
||||||
opts.append({'name': 'comment',
|
|
||||||
'type': 'comment',
|
|
||||||
'value': val})
|
|
||||||
opts.extend(no)
|
|
||||||
val = self._dump_line(self.indent[level], self.subsectdel[1])
|
|
||||||
opts.append({'name': 'comment',
|
|
||||||
'type': 'comment',
|
|
||||||
'value': val})
|
|
||||||
continue
|
|
||||||
if o['type'] == 'option':
|
|
||||||
delim = o.get('delim', self.dassign)
|
|
||||||
if delim not in self.assign:
|
|
||||||
val = self._dump_line(self.indent[level],
|
|
||||||
o['name'],
|
|
||||||
delim,
|
|
||||||
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: [%s]' % 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: [%s]' % 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'] is not None and
|
|
||||||
o['value'] is not no['value']):
|
|
||||||
opts.append(o)
|
|
||||||
continue
|
|
||||||
if no['action'] == 'comment':
|
|
||||||
value = self._dump_line(self.dcomment,
|
|
||||||
o['name'],
|
|
||||||
self.dassign,
|
|
||||||
o['value'])
|
|
||||||
opts.append({'name': 'comment',
|
|
||||||
'type': 'comment',
|
|
||||||
'value': value})
|
|
||||||
continue
|
|
||||||
if no['action'] == 'set':
|
|
||||||
opts.append(no)
|
|
||||||
continue
|
|
||||||
if no['action'] == 'addifnotset':
|
|
||||||
opts.append({
|
|
||||||
'name': 'comment',
|
|
||||||
'type': 'comment',
|
|
||||||
'value': self._dump_line(
|
|
||||||
' ', no['name'], ' modified by IPA'
|
|
||||||
),
|
|
||||||
})
|
|
||||||
opts.append({'name': 'comment', 'type': 'comment',
|
|
||||||
'value': self._dump_line(no['name'],
|
|
||||||
self.dassign,
|
|
||||||
no['value'],
|
|
||||||
)})
|
|
||||||
opts.append(o)
|
|
||||||
continue
|
|
||||||
raise SyntaxError('Unknown action: [%s]' % no['action'])
|
|
||||||
|
|
||||||
raise SyntaxError('Unknown type: [%s]' % 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' or no['action'] == 'addifnotset':
|
|
||||||
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: [%s]' % no['type'])
|
|
||||||
|
|
||||||
def merge(self, oldopts, newopts):
|
|
||||||
"""
|
|
||||||
Uses 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
|
|
||||||
in the newopts tree (this is becaus entire (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.
|
|
||||||
try:
|
|
||||||
curopts.append(self.parseLine(line))
|
|
||||||
except SyntaxError as e:
|
|
||||||
raise SyntaxError('{error} in file {fname}: [{line}]'.format(
|
|
||||||
error=e, fname=f.name, line=line.rstrip()))
|
|
||||||
|
|
||||||
#Add last section if any
|
|
||||||
if len(sectopts) is not 0:
|
|
||||||
opts.append({'name': section,
|
|
||||||
'type': 'section',
|
|
||||||
'value': sectopts})
|
|
||||||
|
|
||||||
return opts
|
|
||||||
|
|
||||||
def changeConf(self, file, newopts):
|
|
||||||
"""
|
|
||||||
Write settings to configuration file
|
|
||||||
:param file: path to the file
|
|
||||||
:param options: set of dictionaries in the form:
|
|
||||||
{'name': 'foo', 'value': 'bar', 'action': 'set/comment'}
|
|
||||||
:param section: section name like 'global'
|
|
||||||
"""
|
|
||||||
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, 0o644)
|
|
||||||
|
|
||||||
oldopts = self.parse(f)
|
|
||||||
|
|
||||||
options = self.merge(oldopts, newopts)
|
|
||||||
|
|
||||||
output = self.dump(options)
|
|
||||||
|
|
||||||
# Write it out and close it.
|
|
||||||
f.seek(0)
|
|
||||||
f.truncate(0)
|
|
||||||
f.write(output)
|
|
||||||
finally:
|
|
||||||
try:
|
|
||||||
if f:
|
|
||||||
f.close()
|
|
||||||
except IOError:
|
|
||||||
pass
|
|
||||||
logger.debug("Updating configuration file %s", file)
|
|
||||||
logger.debug(output)
|
|
||||||
return True
|
|
||||||
|
|
||||||
def newConf(self, file, options, file_perms=0o644):
|
|
||||||
""""
|
|
||||||
Write settings to a new file, backup the old
|
|
||||||
:param file: path to the file
|
|
||||||
:param options: a set of dictionaries in the form:
|
|
||||||
{'name': 'foo', 'value': 'bar', 'action': 'set/comment'}
|
|
||||||
:param file_perms: number defining the new file's permissions
|
|
||||||
"""
|
|
||||||
output = ""
|
|
||||||
f = None
|
|
||||||
try:
|
|
||||||
try:
|
|
||||||
shutil.copy2(file, (file + ".ipabkp"))
|
|
||||||
except IOError as err:
|
|
||||||
if err.errno == 2:
|
|
||||||
# The orign file did not exist
|
|
||||||
pass
|
|
||||||
|
|
||||||
f = openLocked(file, file_perms)
|
|
||||||
|
|
||||||
# Trunkate
|
|
||||||
f.seek(0)
|
|
||||||
f.truncate(0)
|
|
||||||
|
|
||||||
output = self.dump(options)
|
|
||||||
|
|
||||||
f.write(output)
|
|
||||||
finally:
|
|
||||||
try:
|
|
||||||
if f:
|
|
||||||
f.close()
|
|
||||||
except IOError:
|
|
||||||
pass
|
|
||||||
logger.debug("Writing configuration file %s", file)
|
|
||||||
logger.debug(output)
|
|
||||||
return True
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def setOption(name, value):
|
|
||||||
return {'name': name,
|
|
||||||
'type': 'option',
|
|
||||||
'action': 'set',
|
|
||||||
'value': value}
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def rmOption(name):
|
|
||||||
return {'name': name,
|
|
||||||
'type': 'option',
|
|
||||||
'action': 'remove',
|
|
||||||
'value': None}
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def setSection(name, options):
|
|
||||||
return {'name': name,
|
|
||||||
'type': 'section',
|
|
||||||
'action': 'set',
|
|
||||||
'value': options}
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def emptyLine():
|
|
||||||
return {'name': 'empty',
|
|
||||||
'type': 'empty'}
|
|
||||||
|
590
ipapython/ipachangeconf.py
Normal file
590
ipapython/ipachangeconf.py
Normal file
@ -0,0 +1,590 @@
|
|||||||
|
#
|
||||||
|
# ipachangeconf - configuration file manipulation classes and functions
|
||||||
|
# partially based on authconfig code
|
||||||
|
# Copyright (c) 1999-2007 Red Hat, Inc.
|
||||||
|
# Author: Simo Sorce <ssorce@redhat.com>
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
import fcntl
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
import six
|
||||||
|
|
||||||
|
if six.PY3:
|
||||||
|
unicode = str
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
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 as e:
|
||||||
|
if fd != -1:
|
||||||
|
try:
|
||||||
|
os.close(fd)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
raise IOError(e.errno, e.strerror)
|
||||||
|
return os.fdopen(fd, "r+")
|
||||||
|
|
||||||
|
# TODO: add subsection as a concept
|
||||||
|
# (ex. REALM.NAME = { foo = x bar = y } )
|
||||||
|
# TODO: put section delimiters as separating element of the list
|
||||||
|
# so that we can process multiple sections in one go
|
||||||
|
# TODO: add a comment all but provided options as a section option
|
||||||
|
|
||||||
|
|
||||||
|
class IPAChangeConf:
|
||||||
|
def __init__(self, name):
|
||||||
|
self.progname = name
|
||||||
|
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.subsectdel = ("{", "}")
|
||||||
|
self.case_insensitive_sections = True
|
||||||
|
|
||||||
|
def setProgName(self, name):
|
||||||
|
self.progname = name
|
||||||
|
|
||||||
|
def setIndent(self, indent):
|
||||||
|
if type(indent) is tuple:
|
||||||
|
self.indent = indent
|
||||||
|
elif type(indent) is str:
|
||||||
|
self.indent = (indent, )
|
||||||
|
else:
|
||||||
|
raise ValueError('Indent must be a list of strings')
|
||||||
|
|
||||||
|
def setOptionAssignment(self, assign):
|
||||||
|
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 tuple:
|
||||||
|
self.comment = comment
|
||||||
|
else:
|
||||||
|
self.comment = (comment, )
|
||||||
|
self.dcomment = self.comment[0]
|
||||||
|
|
||||||
|
def setEndLine(self, eol):
|
||||||
|
if type(eol) is tuple:
|
||||||
|
self.eol = eol
|
||||||
|
else:
|
||||||
|
self.eol = (eol, )
|
||||||
|
self.deol = self.eol[0]
|
||||||
|
|
||||||
|
def setSectionNameDelimiters(self, delims):
|
||||||
|
self.sectnamdel = delims
|
||||||
|
|
||||||
|
def setSubSectionDelimiters(self, delims):
|
||||||
|
self.subsectdel = delims
|
||||||
|
|
||||||
|
def matchComment(self, line):
|
||||||
|
for v in self.comment:
|
||||||
|
if line.lstrip().startswith(v):
|
||||||
|
return line.lstrip()[len(v):]
|
||||||
|
return False
|
||||||
|
|
||||||
|
def matchEmpty(self, line):
|
||||||
|
if line.strip() == "":
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def matchSection(self, line):
|
||||||
|
cl = "".join(line.strip().split())
|
||||||
|
cl = cl.lower() if self.case_insensitive_sections else cl
|
||||||
|
|
||||||
|
if len(self.sectnamdel) != 2:
|
||||||
|
return False
|
||||||
|
if not cl.startswith(self.sectnamdel[0]):
|
||||||
|
return False
|
||||||
|
if not cl.endswith(self.sectnamdel[1]):
|
||||||
|
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._dump_line(self.sectnamdel[0],
|
||||||
|
section,
|
||||||
|
self.sectnamdel[1],
|
||||||
|
self.deol)
|
||||||
|
|
||||||
|
def _dump_line(self, *args):
|
||||||
|
return u"".join(unicode(x) for x in args)
|
||||||
|
|
||||||
|
def dump(self, options, level=0):
|
||||||
|
output = []
|
||||||
|
if level >= len(self.indent):
|
||||||
|
level = len(self.indent) - 1
|
||||||
|
|
||||||
|
for o in options:
|
||||||
|
if o['type'] == "section":
|
||||||
|
output.append(self._dump_line(self.sectnamdel[0],
|
||||||
|
o['name'],
|
||||||
|
self.sectnamdel[1]))
|
||||||
|
output.append(self.dump(o['value'], (level + 1)))
|
||||||
|
continue
|
||||||
|
if o['type'] == "subsection":
|
||||||
|
output.append(self._dump_line(self.indent[level],
|
||||||
|
o['name'],
|
||||||
|
self.dassign,
|
||||||
|
self.subsectdel[0]))
|
||||||
|
output.append(self.dump(o['value'], (level + 1)))
|
||||||
|
output.append(self._dump_line(self.indent[level],
|
||||||
|
self.subsectdel[1]))
|
||||||
|
continue
|
||||||
|
if o['type'] == "option":
|
||||||
|
delim = o.get('delim', self.dassign)
|
||||||
|
if delim not in self.assign:
|
||||||
|
raise ValueError(
|
||||||
|
'Unknown delim "%s" must be one of "%s"' %
|
||||||
|
(delim, " ".join([d for d in self.assign]))
|
||||||
|
)
|
||||||
|
output.append(self._dump_line(self.indent[level],
|
||||||
|
o['name'],
|
||||||
|
delim,
|
||||||
|
o['value']))
|
||||||
|
continue
|
||||||
|
if o['type'] == "comment":
|
||||||
|
output.append(self._dump_line(self.dcomment, o['value']))
|
||||||
|
continue
|
||||||
|
if o['type'] == "empty":
|
||||||
|
output.append('')
|
||||||
|
continue
|
||||||
|
raise SyntaxError('Unknown type: [%s]' % o['type'])
|
||||||
|
|
||||||
|
# append an empty string to the output so that we add eol to the end
|
||||||
|
# of the file contents in a single join()
|
||||||
|
output.append('')
|
||||||
|
return self.deol.join(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()} # pylint: disable=E1103
|
||||||
|
|
||||||
|
o = dict()
|
||||||
|
parts = line.split(self.dassign, 1)
|
||||||
|
if len(parts) < 2:
|
||||||
|
# The default assign didn't match, try the non-default
|
||||||
|
for d in self.assign[1:]:
|
||||||
|
parts = line.split(d, 1)
|
||||||
|
if len(parts) >= 2:
|
||||||
|
o['delim'] = d
|
||||||
|
break
|
||||||
|
|
||||||
|
if 'delim' not in o:
|
||||||
|
raise SyntaxError('Syntax Error: Unknown line format')
|
||||||
|
|
||||||
|
o.update({'name': parts[0].strip(), 'type': 'option',
|
||||||
|
'value': parts[1].rstrip()})
|
||||||
|
return o
|
||||||
|
|
||||||
|
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._dump_line(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._dump_line(self.indent[level],
|
||||||
|
o['name'],
|
||||||
|
self.dassign,
|
||||||
|
self.subsectdel[0])
|
||||||
|
opts.append({'name': 'comment',
|
||||||
|
'type': 'comment',
|
||||||
|
'value': val})
|
||||||
|
opts.extend(no)
|
||||||
|
val = self._dump_line(self.indent[level], self.subsectdel[1])
|
||||||
|
opts.append({'name': 'comment',
|
||||||
|
'type': 'comment',
|
||||||
|
'value': val})
|
||||||
|
continue
|
||||||
|
if o['type'] == 'option':
|
||||||
|
delim = o.get('delim', self.dassign)
|
||||||
|
if delim not in self.assign:
|
||||||
|
val = self._dump_line(self.indent[level],
|
||||||
|
o['name'],
|
||||||
|
delim,
|
||||||
|
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: [%s]' % 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: [%s]' % 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'] is not None and
|
||||||
|
o['value'] is not no['value']):
|
||||||
|
opts.append(o)
|
||||||
|
continue
|
||||||
|
if no['action'] == 'comment':
|
||||||
|
value = self._dump_line(self.dcomment,
|
||||||
|
o['name'],
|
||||||
|
self.dassign,
|
||||||
|
o['value'])
|
||||||
|
opts.append({'name': 'comment',
|
||||||
|
'type': 'comment',
|
||||||
|
'value': value})
|
||||||
|
continue
|
||||||
|
if no['action'] == 'set':
|
||||||
|
opts.append(no)
|
||||||
|
continue
|
||||||
|
if no['action'] == 'addifnotset':
|
||||||
|
opts.append({
|
||||||
|
'name': 'comment',
|
||||||
|
'type': 'comment',
|
||||||
|
'value': self._dump_line(
|
||||||
|
' ', no['name'], ' modified by IPA'
|
||||||
|
),
|
||||||
|
})
|
||||||
|
opts.append({'name': 'comment', 'type': 'comment',
|
||||||
|
'value': self._dump_line(no['name'],
|
||||||
|
self.dassign,
|
||||||
|
no['value'],
|
||||||
|
)})
|
||||||
|
opts.append(o)
|
||||||
|
continue
|
||||||
|
raise SyntaxError('Unknown action: [%s]' % no['action'])
|
||||||
|
|
||||||
|
raise SyntaxError('Unknown type: [%s]' % 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' or no['action'] == 'addifnotset':
|
||||||
|
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: [%s]' % no['type'])
|
||||||
|
|
||||||
|
def merge(self, oldopts, newopts):
|
||||||
|
"""
|
||||||
|
Uses 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
|
||||||
|
in the newopts tree (this is becaus entire (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.
|
||||||
|
try:
|
||||||
|
curopts.append(self.parseLine(line))
|
||||||
|
except SyntaxError as e:
|
||||||
|
raise SyntaxError('{error} in file {fname}: [{line}]'.format(
|
||||||
|
error=e, fname=f.name, line=line.rstrip()))
|
||||||
|
|
||||||
|
# Add last section if any
|
||||||
|
if len(sectopts) is not 0:
|
||||||
|
opts.append({'name': section,
|
||||||
|
'type': 'section',
|
||||||
|
'value': sectopts})
|
||||||
|
|
||||||
|
return opts
|
||||||
|
|
||||||
|
def changeConf(self, file, newopts):
|
||||||
|
"""
|
||||||
|
Write settings to configuration file
|
||||||
|
:param file: path to the file
|
||||||
|
:param options: set of dictionaries in the form:
|
||||||
|
{'name': 'foo', 'value': 'bar', 'action': 'set/comment'}
|
||||||
|
:param section: section name like 'global'
|
||||||
|
"""
|
||||||
|
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, 0o644)
|
||||||
|
|
||||||
|
oldopts = self.parse(f)
|
||||||
|
|
||||||
|
options = self.merge(oldopts, newopts)
|
||||||
|
|
||||||
|
output = self.dump(options)
|
||||||
|
|
||||||
|
# Write it out and close it.
|
||||||
|
f.seek(0)
|
||||||
|
f.truncate(0)
|
||||||
|
f.write(output)
|
||||||
|
finally:
|
||||||
|
try:
|
||||||
|
if f:
|
||||||
|
f.close()
|
||||||
|
except IOError:
|
||||||
|
pass
|
||||||
|
logger.debug("Updating configuration file %s", file)
|
||||||
|
logger.debug(output)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def newConf(self, file, options, file_perms=0o644):
|
||||||
|
""""
|
||||||
|
Write settings to a new file, backup the old
|
||||||
|
:param file: path to the file
|
||||||
|
:param options: a set of dictionaries in the form:
|
||||||
|
{'name': 'foo', 'value': 'bar', 'action': 'set/comment'}
|
||||||
|
:param file_perms: number defining the new file's permissions
|
||||||
|
"""
|
||||||
|
output = ""
|
||||||
|
f = None
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
shutil.copy2(file, (file + ".ipabkp"))
|
||||||
|
except IOError as err:
|
||||||
|
if err.errno == 2:
|
||||||
|
# The orign file did not exist
|
||||||
|
pass
|
||||||
|
|
||||||
|
f = openLocked(file, file_perms)
|
||||||
|
|
||||||
|
# Trunkate
|
||||||
|
f.seek(0)
|
||||||
|
f.truncate(0)
|
||||||
|
|
||||||
|
output = self.dump(options)
|
||||||
|
|
||||||
|
f.write(output)
|
||||||
|
finally:
|
||||||
|
try:
|
||||||
|
if f:
|
||||||
|
f.close()
|
||||||
|
except IOError:
|
||||||
|
pass
|
||||||
|
logger.debug("Writing configuration file %s", file)
|
||||||
|
logger.debug(output)
|
||||||
|
return True
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def setOption(name, value):
|
||||||
|
return {'name': name,
|
||||||
|
'type': 'option',
|
||||||
|
'action': 'set',
|
||||||
|
'value': value}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def rmOption(name):
|
||||||
|
return {'name': name,
|
||||||
|
'type': 'option',
|
||||||
|
'action': 'remove',
|
||||||
|
'value': None}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def setSection(name, options):
|
||||||
|
return {'name': name,
|
||||||
|
'type': 'section',
|
||||||
|
'action': 'set',
|
||||||
|
'value': options}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def emptyLine():
|
||||||
|
return {'name': 'empty',
|
||||||
|
'type': 'empty'}
|
@ -40,11 +40,11 @@ from ipaserver.install.replication import wait_for_task
|
|||||||
from ipalib import errors, api
|
from ipalib import errors, api
|
||||||
from ipalib.util import normalize_zone
|
from ipalib.util import normalize_zone
|
||||||
from ipapython.dn import DN
|
from ipapython.dn import DN
|
||||||
|
from ipapython import ipachangeconf
|
||||||
from ipapython import ipaldap
|
from ipapython import ipaldap
|
||||||
from ipapython import ipautil
|
from ipapython import ipautil
|
||||||
import ipapython.errors
|
import ipapython.errors
|
||||||
|
|
||||||
import ipaclient.install.ipachangeconf
|
|
||||||
from ipaplatform import services
|
from ipaplatform import services
|
||||||
from ipaplatform.constants import constants
|
from ipaplatform.constants import constants
|
||||||
from ipaplatform.paths import paths
|
from ipaplatform.paths import paths
|
||||||
@ -639,7 +639,7 @@ class ADTRUSTInstance(service.Service):
|
|||||||
self.print_msg("Cannot modify /etc/krb5.conf")
|
self.print_msg("Cannot modify /etc/krb5.conf")
|
||||||
|
|
||||||
krbconf = (
|
krbconf = (
|
||||||
ipaclient.install.ipachangeconf.IPAChangeConf("IPA Installer"))
|
ipachangeconf.IPAChangeConf("IPA Installer"))
|
||||||
krbconf.setOptionAssignment((" = ", " "))
|
krbconf.setOptionAssignment((" = ", " "))
|
||||||
krbconf.setSectionNameDelimiters(("[", "]"))
|
krbconf.setSectionNameDelimiters(("[", "]"))
|
||||||
krbconf.setSubSectionDelimiters(("{", "}"))
|
krbconf.setSubSectionDelimiters(("{", "}"))
|
||||||
|
@ -19,7 +19,7 @@ import six
|
|||||||
from ipaclient.install import timeconf
|
from ipaclient.install import timeconf
|
||||||
from ipaclient.install.client import (
|
from ipaclient.install.client import (
|
||||||
check_ldap_conf, sync_time, restore_time_sync)
|
check_ldap_conf, sync_time, restore_time_sync)
|
||||||
from ipaclient.install.ipachangeconf import IPAChangeConf
|
from ipapython.ipachangeconf import IPAChangeConf
|
||||||
from ipalib.install import certmonger, sysrestore
|
from ipalib.install import certmonger, sysrestore
|
||||||
from ipapython import ipautil, version
|
from ipapython import ipautil, version
|
||||||
from ipapython.ipautil import (
|
from ipapython.ipautil import (
|
||||||
|
@ -23,13 +23,13 @@ from pkg_resources import parse_version
|
|||||||
import six
|
import six
|
||||||
|
|
||||||
from ipaclient.install.client import check_ldap_conf
|
from ipaclient.install.client import check_ldap_conf
|
||||||
from ipaclient.install.ipachangeconf import IPAChangeConf
|
|
||||||
import ipaclient.install.timeconf
|
import ipaclient.install.timeconf
|
||||||
from ipalib.install import certstore, sysrestore
|
from ipalib.install import certstore, sysrestore
|
||||||
from ipalib.install.kinit import kinit_keytab
|
from ipalib.install.kinit import kinit_keytab
|
||||||
from ipapython import ipaldap, ipautil
|
from ipapython import ipaldap, ipautil
|
||||||
from ipapython.dn import DN
|
from ipapython.dn import DN
|
||||||
from ipapython.admintool import ScriptError
|
from ipapython.admintool import ScriptError
|
||||||
|
from ipapython.ipachangeconf import IPAChangeConf
|
||||||
from ipaplatform import services
|
from ipaplatform import services
|
||||||
from ipaplatform.tasks import tasks
|
from ipaplatform.tasks import tasks
|
||||||
from ipaplatform.paths import paths
|
from ipaplatform.paths import paths
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from ipaclient.install.ipachangeconf import IPAChangeConf
|
from ipapython.ipachangeconf import IPAChangeConf
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope='function')
|
@pytest.fixture(scope='function')
|
||||||
|
Loading…
Reference in New Issue
Block a user