From 6ab8aaff8adefe8fe4b588fac16d3f1c1e0b0715 Mon Sep 17 00:00:00 2001 From: Alexander Sulfrian Date: Thu, 10 Jun 2021 20:55:41 +0200 Subject: debconf: Add client tool --- src/lib/Bcfg2/Client/Tools/Debconf.py | 102 ++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 src/lib/Bcfg2/Client/Tools/Debconf.py (limited to 'src/lib/Bcfg2/Client') diff --git a/src/lib/Bcfg2/Client/Tools/Debconf.py b/src/lib/Bcfg2/Client/Tools/Debconf.py new file mode 100644 index 000000000..147d58b4b --- /dev/null +++ b/src/lib/Bcfg2/Client/Tools/Debconf.py @@ -0,0 +1,102 @@ +"""Debconf Support for Bcfg2""" + +import subprocess +import Bcfg2.Options +import Bcfg2.Client.Tools + + +class Debconf(Bcfg2.Client.Tools.Tool): + """Debconf Support for Bcfg2.""" + name = 'Debconf' + __execs__ = ['/usr/bin/debconf-communicate'] + __handles__ = [('Conf', 'debconf')] + __req__ = {'Conf': ['name']} + + def __init__(self, config): + Bcfg2.Client.Tools.Tool.__init__(self, config) + + #: This is the referrence to the Popen object of the + #: running debconf-communicate process. If this is None, + #: no process is runnning. + self.debconf = None + + def _start_debconf(self): + if self.debconf is None: + self.debconf = subprocess.Popen( + ['/usr/bin/debconf-communicate'], + stdin=subprocess.PIPE, stdout=subprocess.PIPE) + + def _stop_debconf(self): + if self.debconf is not None: + self.debconf.stdin.close() + self.debconf.stdout.close() + self.debconf = None + + def _debconf_reply(self, msg): + self.logger.debug('Debconf: %s' % msg.strip()) + self.debconf.stdin.write(msg) + line = self.debconf.stdout.readline().rstrip('\n') + self.logger.debug('< %s' % line) + reply = line.split(' ', 1) + + result = None + if len(reply) > 1: + result = reply[1] + return (reply[0] == '0', result) + + def debconf_get(self, key): + (success, value) = self._debconf_reply('GET %s\n' % key) + if not success: + return (False, None) + + (_, seen) = self._debconf_reply('FGET %s seen\n' % key) + return (seen, value) + + def debconf_set(self, key, value): + (success, _) = self._debconf_reply('SET %s %s\n' % (key, value)) + if success: + self._debconf_reply('FSET %s seen true\n' % key) + + return success + + def debconf_reset(self, key): + (success, _) = self._debconf_reply('RESET %s\n' % key) + return success + + def VerifyConf(self, entry, _modlist): + """ Verify the given Debconf entry. """ + (seen, value) = self.debconf_get(entry.get('name')) + if 'value' not in entry.attrib: + if seen == 'true': + return False + else: + if value != entry.get('value'): + return False + return True + + def InstallConf(self, entry): + """ Install the given Debconf entry. """ + if 'value' not in entry.attrib: + return self.debconf_reset(entry.get('name')) + + return self.debconf_set(entry.get('name'), entry.get('value')) + + def Inventory(self, structures=None): + try: + self._start_debconf() + result = Bcfg2.Client.Tools.Tool.Inventory(self, structures) + finally: + self._stop_debconf() + + return result + Inventory.__doc__ = Bcfg2.Client.Tools.Tool.Inventory.__doc__ + + def Install(self, entries): + try: + self._start_debconf() + result = Bcfg2.Client.Tools.Tool.Install(self, entries) + finally: + self._stop_debconf() + + return result + Install.__doc__ = Bcfg2.Client.Tools.Tool.Install.__doc__ -- cgit v1.2.3-1-g7c22 From 161953cb28f356e1aa38f5cf67234f28a19ceb26 Mon Sep 17 00:00:00 2001 From: Alexander Sulfrian Date: Fri, 18 Jun 2021 17:07:40 +0200 Subject: debconf: Find extra entries Extra debconf entries, are entries that were seen but that are not specified in the configuration. --- src/lib/Bcfg2/Client/Tools/Debconf.py | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) (limited to 'src/lib/Bcfg2/Client') diff --git a/src/lib/Bcfg2/Client/Tools/Debconf.py b/src/lib/Bcfg2/Client/Tools/Debconf.py index 147d58b4b..4e8797b1c 100644 --- a/src/lib/Bcfg2/Client/Tools/Debconf.py +++ b/src/lib/Bcfg2/Client/Tools/Debconf.py @@ -8,7 +8,7 @@ import Bcfg2.Client.Tools class Debconf(Bcfg2.Client.Tools.Tool): """Debconf Support for Bcfg2.""" name = 'Debconf' - __execs__ = ['/usr/bin/debconf-communicate'] + __execs__ = ['/usr/bin/debconf-communicate', '/usr/bin/debconf-show'] __handles__ = [('Conf', 'debconf')] __req__ = {'Conf': ['name']} @@ -65,20 +65,13 @@ class Debconf(Bcfg2.Client.Tools.Tool): def VerifyConf(self, entry, _modlist): """ Verify the given Debconf entry. """ - (seen, value) = self.debconf_get(entry.get('name')) - if 'value' not in entry.attrib: - if seen == 'true': - return False - else: - if value != entry.get('value'): - return False + (_, value) = self.debconf_get(entry.get('name')) + if value != entry.get('value'): + return False return True def InstallConf(self, entry): """ Install the given Debconf entry. """ - if 'value' not in entry.attrib: - return self.debconf_reset(entry.get('name')) - return self.debconf_set(entry.get('name'), entry.get('value')) def Inventory(self, structures=None): @@ -100,3 +93,21 @@ class Debconf(Bcfg2.Client.Tools.Tool): return result Install.__doc__ = Bcfg2.Client.Tools.Tool.Install.__doc__ + + def FindExtra(self): + specified = [entry.get('name') + for entry in self.getSupportedEntries()] + extra = set() + listowners = self.cmd.run(['/usr/bin/debconf-show', '--listowners']) + if listowners.success: + owners = listowners.stdout.splitlines() + + values = self.cmd.run(['/usr/bin/debconf-show'] + owners) + for line in values.stdout.splitlines(): + if len(line) > 2 and line[0] == '*': + (name, value) = line[2:].split(':', 2) + if name not in specified: + extra.add(name) + return [Bcfg2.Client.XML.Element('Conf', name=name, type='debconf') + for name in list(extra)] + FindExtra.__doc__ = Bcfg2.Client.Tools.Tool.FindExtra.__doc__ -- cgit v1.2.3-1-g7c22 From 528eae28bb320e4aa5747adcdd8953c308872ef4 Mon Sep 17 00:00:00 2001 From: Alexander Sulfrian Date: Sun, 16 Jan 2022 02:06:14 +0100 Subject: debconf: Only start communicate process on demand --- src/lib/Bcfg2/Client/Tools/Debconf.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/lib/Bcfg2/Client') diff --git a/src/lib/Bcfg2/Client/Tools/Debconf.py b/src/lib/Bcfg2/Client/Tools/Debconf.py index 4e8797b1c..76d745610 100644 --- a/src/lib/Bcfg2/Client/Tools/Debconf.py +++ b/src/lib/Bcfg2/Client/Tools/Debconf.py @@ -33,6 +33,9 @@ class Debconf(Bcfg2.Client.Tools.Tool): self.debconf = None def _debconf_reply(self, msg): + if self.debconf is None: + self._start_debconf() + self.logger.debug('Debconf: %s' % msg.strip()) self.debconf.stdin.write(msg) line = self.debconf.stdout.readline().rstrip('\n') @@ -76,7 +79,6 @@ class Debconf(Bcfg2.Client.Tools.Tool): def Inventory(self, structures=None): try: - self._start_debconf() result = Bcfg2.Client.Tools.Tool.Inventory(self, structures) finally: self._stop_debconf() @@ -86,7 +88,6 @@ class Debconf(Bcfg2.Client.Tools.Tool): def Install(self, entries): try: - self._start_debconf() result = Bcfg2.Client.Tools.Tool.Install(self, entries) finally: self._stop_debconf() -- cgit v1.2.3-1-g7c22 From aac1945e6a4a2a94736e2a2ff7a761121cb65a19 Mon Sep 17 00:00:00 2001 From: Alexander Sulfrian Date: Sun, 16 Jan 2022 02:35:00 +0100 Subject: debconf: Save current_value for reporting --- src/lib/Bcfg2/Client/Tools/Debconf.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'src/lib/Bcfg2/Client') diff --git a/src/lib/Bcfg2/Client/Tools/Debconf.py b/src/lib/Bcfg2/Client/Tools/Debconf.py index 76d745610..0d286028b 100644 --- a/src/lib/Bcfg2/Client/Tools/Debconf.py +++ b/src/lib/Bcfg2/Client/Tools/Debconf.py @@ -68,10 +68,9 @@ class Debconf(Bcfg2.Client.Tools.Tool): def VerifyConf(self, entry, _modlist): """ Verify the given Debconf entry. """ - (_, value) = self.debconf_get(entry.get('name')) - if value != entry.get('value'): - return False - return True + (_, current_value) = self.debconf_get(entry.get('name')) + entry.set('current_value', current_value) + return current_value == entry.get('value') def InstallConf(self, entry): """ Install the given Debconf entry. """ @@ -98,7 +97,7 @@ class Debconf(Bcfg2.Client.Tools.Tool): def FindExtra(self): specified = [entry.get('name') for entry in self.getSupportedEntries()] - extra = set() + extra = dict() listowners = self.cmd.run(['/usr/bin/debconf-show', '--listowners']) if listowners.success: owners = listowners.stdout.splitlines() @@ -106,9 +105,10 @@ class Debconf(Bcfg2.Client.Tools.Tool): values = self.cmd.run(['/usr/bin/debconf-show'] + owners) for line in values.stdout.splitlines(): if len(line) > 2 and line[0] == '*': - (name, value) = line[2:].split(':', 2) - if name not in specified: - extra.add(name) - return [Bcfg2.Client.XML.Element('Conf', name=name, type='debconf') - for name in list(extra)] + (name, current_value) = line[2:].split(':', 2) + if name not in specified and name not in extra: + extra[name] = Bcfg2.Client.XML.Element( + 'Conf', name=name, type='debconf', + current_value=current_value[1:]) + return extra.values() FindExtra.__doc__ = Bcfg2.Client.Tools.Tool.FindExtra.__doc__ -- cgit v1.2.3-1-g7c22 From 49cf4482ea952de6bcf3c023c017309cd7926c15 Mon Sep 17 00:00:00 2001 From: Alexander Sulfrian Date: Sat, 29 Jan 2022 19:59:03 +0100 Subject: debconf: Add ability to ignore conf settings --- src/lib/Bcfg2/Client/Tools/Debconf.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/lib/Bcfg2/Client') diff --git a/src/lib/Bcfg2/Client/Tools/Debconf.py b/src/lib/Bcfg2/Client/Tools/Debconf.py index 0d286028b..706f7a8dc 100644 --- a/src/lib/Bcfg2/Client/Tools/Debconf.py +++ b/src/lib/Bcfg2/Client/Tools/Debconf.py @@ -68,6 +68,9 @@ class Debconf(Bcfg2.Client.Tools.Tool): def VerifyConf(self, entry, _modlist): """ Verify the given Debconf entry. """ + if entry.get('ignore', 'false').lower() == 'true': + return True + (_, current_value) = self.debconf_get(entry.get('name')) entry.set('current_value', current_value) return current_value == entry.get('value') -- cgit v1.2.3-1-g7c22 From a4bd3e3b55cc842b50075e9cae912f7dc9e9cfa2 Mon Sep 17 00:00:00 2001 From: Alexander Sulfrian Date: Sun, 30 Jan 2022 05:00:21 +0100 Subject: debconf: Support removing of conf entries --- src/lib/Bcfg2/Client/Tools/Debconf.py | 12 +++++++++++- src/lib/Bcfg2/Client/__init__.py | 5 ++++- 2 files changed, 15 insertions(+), 2 deletions(-) (limited to 'src/lib/Bcfg2/Client') diff --git a/src/lib/Bcfg2/Client/Tools/Debconf.py b/src/lib/Bcfg2/Client/Tools/Debconf.py index 706f7a8dc..2dc88e748 100644 --- a/src/lib/Bcfg2/Client/Tools/Debconf.py +++ b/src/lib/Bcfg2/Client/Tools/Debconf.py @@ -96,7 +96,17 @@ class Debconf(Bcfg2.Client.Tools.Tool): return result Install.__doc__ = Bcfg2.Client.Tools.Tool.Install.__doc__ - + + def Remove(self, entries): + try: + for entry in entries: + self.debconf_reset(entry.get('name')) + self.modified += entry + finally: + self._stop_debconf() + self.extra = self.FindExtra() + Remove.__doc__ = Bcfg2.Client.Tools.Tool.Remove.__doc__ + def FindExtra(self): specified = [entry.get('name') for entry in self.getSupportedEntries()] diff --git a/src/lib/Bcfg2/Client/__init__.py b/src/lib/Bcfg2/Client/__init__.py index 157cc7f65..a7e0dade5 100644 --- a/src/lib/Bcfg2/Client/__init__.py +++ b/src/lib/Bcfg2/Client/__init__.py @@ -110,7 +110,7 @@ class Client(object): help='Only verify the given bundle(s)'), Bcfg2.Options.Option( '-r', '--remove', - choices=['all', 'services', 'packages', 'users'], + choices=['all', 'services', 'packages', 'users', 'conf'], help='Force removal of additional configuration items')), Bcfg2.Options.ExclusiveOptionGroup( Bcfg2.Options.PathOption( @@ -640,6 +640,9 @@ class Client(object): elif Bcfg2.Options.setup.remove == 'users': self.removal = [entry for entry in self.extra if entry.tag in ['POSIXUser', 'POSIXGroup']] + elif Bcfg2.Options.setup.remove == 'conf': + self.removal = [entry for entry in self.extra + if entry.tag == 'Conf'] candidates = [entry for entry in self.states if not self.states[entry]] -- cgit v1.2.3-1-g7c22 From c11f4f790d710721dcc99f87cfcbafb49e9a4715 Mon Sep 17 00:00:00 2001 From: Alexander Sulfrian Date: Sun, 30 Jan 2022 04:54:49 +0100 Subject: debconf: Verify seen value --- src/lib/Bcfg2/Client/Tools/Debconf.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'src/lib/Bcfg2/Client') diff --git a/src/lib/Bcfg2/Client/Tools/Debconf.py b/src/lib/Bcfg2/Client/Tools/Debconf.py index 2dc88e748..784f7e9bc 100644 --- a/src/lib/Bcfg2/Client/Tools/Debconf.py +++ b/src/lib/Bcfg2/Client/Tools/Debconf.py @@ -53,7 +53,7 @@ class Debconf(Bcfg2.Client.Tools.Tool): return (False, None) (_, seen) = self._debconf_reply('FGET %s seen\n' % key) - return (seen, value) + return (seen == 'true', value) def debconf_set(self, key, value): (success, _) = self._debconf_reply('SET %s %s\n' % (key, value)) @@ -71,9 +71,12 @@ class Debconf(Bcfg2.Client.Tools.Tool): if entry.get('ignore', 'false').lower() == 'true': return True - (_, current_value) = self.debconf_get(entry.get('name')) + (seen, current_value) = self.debconf_get(entry.get('name')) + if not seen: + current_value = '%s (not seen)' % current_value entry.set('current_value', current_value) - return current_value == entry.get('value') + + return seen and current_value == entry.get('value') def InstallConf(self, entry): """ Install the given Debconf entry. """ -- cgit v1.2.3-1-g7c22