diff options
Diffstat (limited to 'src/lib/Bcfg2/Client')
-rw-r--r-- | src/lib/Bcfg2/Client/Frame.py | 22 | ||||
-rw-r--r-- | src/lib/Bcfg2/Client/Tools/Chkconfig.py | 96 | ||||
-rw-r--r-- | src/lib/Bcfg2/Client/Tools/DebInit.py | 103 | ||||
-rw-r--r-- | src/lib/Bcfg2/Client/Tools/POSIX/Directory.py | 6 | ||||
-rw-r--r-- | src/lib/Bcfg2/Client/Tools/POSIXUsers.py | 6 | ||||
-rw-r--r-- | src/lib/Bcfg2/Client/Tools/Portage.py | 8 | ||||
-rw-r--r-- | src/lib/Bcfg2/Client/Tools/RcUpdate.py | 108 | ||||
-rw-r--r-- | src/lib/Bcfg2/Client/Tools/Systemd.py | 2 | ||||
-rw-r--r-- | src/lib/Bcfg2/Client/Tools/__init__.py | 16 | ||||
-rw-r--r-- | src/lib/Bcfg2/Client/__init__.py | 2 |
10 files changed, 252 insertions, 117 deletions
diff --git a/src/lib/Bcfg2/Client/Frame.py b/src/lib/Bcfg2/Client/Frame.py index 850e58d9d..6bef77081 100644 --- a/src/lib/Bcfg2/Client/Frame.py +++ b/src/lib/Bcfg2/Client/Frame.py @@ -6,15 +6,7 @@ import fnmatch import logging import Bcfg2.Client.Tools from Bcfg2.Client import prompt -from Bcfg2.Compat import any, all, cmp # pylint: disable=W0622 - - -def cmpent(ent1, ent2): - """Sort entries.""" - if ent1.tag != ent2.tag: - return cmp(ent1.tag, ent2.tag) - else: - return cmp(ent1.get('name'), ent2.get('name')) +from Bcfg2.Compat import any, all # pylint: disable=W0622 def matches_entry(entryspec, entry): @@ -105,8 +97,8 @@ class Frame(object): self.logger.warning(deprecated) experimental = [tool.name for tool in self.tools if tool.experimental] if experimental: - self.logger.warning("Loaded experimental tool drivers:") - self.logger.warning(experimental) + self.logger.info("Loaded experimental tool drivers:") + self.logger.info(experimental) # find entries not handled by any tools self.unhandled = [entry for struct in config @@ -155,7 +147,7 @@ class Frame(object): def promptFilter(self, msg, entries): """Filter a supplied list based on user input.""" ret = [] - entries.sort(cmpent) + entries.sort(key=lambda e: e.tag + ":" + e.get('name')) for entry in entries[:]: if entry in self.unhandled: # don't prompt for entries that can't be installed @@ -418,10 +410,12 @@ class Frame(object): # prune out unspecified bundles when running with -b continue if bundle in mbundles: - self.logger.debug("Bundle %s was modified" % bundle) + self.logger.debug("Bundle %s was modified" % + bundle.get('name')) func = "BundleUpdated" else: - self.logger.debug("Bundle %s was not modified" % bundle) + self.logger.debug("Bundle %s was not modified" % + bundle.get('name')) func = "BundleNotUpdated" for tool in self.tools: try: diff --git a/src/lib/Bcfg2/Client/Tools/Chkconfig.py b/src/lib/Bcfg2/Client/Tools/Chkconfig.py index ec7f462b3..256c28255 100644 --- a/src/lib/Bcfg2/Client/Tools/Chkconfig.py +++ b/src/lib/Bcfg2/Client/Tools/Chkconfig.py @@ -19,25 +19,22 @@ class Chkconfig(Bcfg2.Client.Tools.SvcTool): def get_svc_command(self, service, action): return "/sbin/service %s %s" % (service.get('name'), action) - def VerifyService(self, entry, _): - """Verify Service status for entry.""" - if entry.get('status') == 'ignore': - return True - + def verify_bootstatus(self, entry, bootstatus): + """Verify bootstatus for entry.""" rv = self.cmd.run("/sbin/chkconfig --list %s " % entry.get('name')) if rv.success: srvdata = rv.stdout.splitlines()[0].split() else: # service not installed - entry.set('current_status', 'off') + entry.set('current_bootstatus', 'service not installed') return False if len(srvdata) == 2: # This is an xinetd service - if entry.get('status') == srvdata[1]: + if bootstatus == srvdata[1]: return True else: - entry.set('current_status', srvdata[1]) + entry.set('current_bootstatus', srvdata[1]) return False try: @@ -46,37 +43,74 @@ class Chkconfig(Bcfg2.Client.Tools.SvcTool): except IndexError: onlevels = [] - pstatus = self.check_service(entry) - if entry.get('status') == 'on': - status = (len(onlevels) > 0 and pstatus) + if bootstatus == 'on': + current_bootstatus = (len(onlevels) > 0) else: - status = (len(onlevels) == 0 and not pstatus) + current_bootstatus = (len(onlevels) == 0) + return current_bootstatus + + def VerifyService(self, entry, _): + """Verify Service status for entry.""" + entry.set('target_status', entry.get('status')) # for reporting + bootstatus = self.get_bootstatus(entry) + if bootstatus is None: + return True + current_bootstatus = self.verify_bootstatus(entry, bootstatus) - if not status: + if entry.get('status') == 'ignore': + # 'ignore' should verify + current_svcstatus = True + else: + svcstatus = self.check_service(entry) if entry.get('status') == 'on': - entry.set('current_status', 'off') - else: - entry.set('current_status', 'on') - return status + if svcstatus: + current_svcstatus = True + else: + current_svcstatus = False + elif entry.get('status') == 'off': + if svcstatus: + current_svcstatus = False + else: + current_svcstatus = True + + if svcstatus: + entry.set('current_status', 'on') + else: + entry.set('current_status', 'off') + + return current_bootstatus and current_svcstatus def InstallService(self, entry): """Install Service entry.""" - rcmd = "/sbin/chkconfig %s %s" - self.cmd.run("/sbin/chkconfig --add %s" % (entry.attrib['name'])) + self.cmd.run("/sbin/chkconfig --add %s" % (entry.get('name'))) self.logger.info("Installing Service %s" % (entry.get('name'))) - rv = True - if entry.get('status') == 'off': - rv &= self.cmd.run((rcmd + " --level 0123456") % - (entry.get('name'), - entry.get('status'))).success - if entry.get("current_status") == "on": - rv &= self.stop_service(entry).success + bootstatus = entry.get('bootstatus') + if bootstatus is not None: + if bootstatus == 'on': + # make sure service is enabled on boot + bootcmd = '/sbin/chkconfig %s %s --level 0123456' % \ + (entry.get('name'), entry.get('bootstatus')) + elif bootstatus == 'off': + # make sure service is disabled on boot + bootcmd = '/sbin/chkconfig %s %s' % (entry.get('name'), + entry.get('bootstatus')) + bootcmdrv = self.cmd.run(bootcmd).success + if self.setup['servicemode'] == 'disabled': + # 'disabled' means we don't attempt to modify running svcs + return bootcmdrv + buildmode = self.setup['servicemode'] == 'build' + if (entry.get('status') == 'on' and not buildmode) and \ + entry.get('current_status') == 'off': + svccmdrv = self.start_service(entry) + elif (entry.get('status') == 'off' or buildmode) and \ + entry.get('current_status') == 'on': + svccmdrv = self.stop_service(entry) + else: + svccmdrv = True # ignore status attribute + return bootcmdrv and svccmdrv else: - rv &= self.cmd.run(rcmd % (entry.get('name'), - entry.get('status'))).success - if entry.get("current_status") == "off": - rv &= self.start_service(entry).success - return rv + # when bootstatus is 'None', status == 'ignore' + return True def FindExtra(self): """Locate extra chkconfig Services.""" diff --git a/src/lib/Bcfg2/Client/Tools/DebInit.py b/src/lib/Bcfg2/Client/Tools/DebInit.py index d916b1662..761c51db7 100644 --- a/src/lib/Bcfg2/Client/Tools/DebInit.py +++ b/src/lib/Bcfg2/Client/Tools/DebInit.py @@ -18,13 +18,11 @@ class DebInit(Bcfg2.Client.Tools.SvcTool): svcre = \ re.compile(r'/etc/.*/(?P<action>[SK])(?P<sequence>\d+)(?P<name>\S+)') - # implement entry (Verify|Install) ops - def VerifyService(self, entry, _): - """Verify Service status for entry.""" - - if entry.get('status') == 'ignore': - return True + def get_svc_command(self, service, action): + return '/usr/sbin/invoke-rc.d %s %s' % (service.get('name'), action) + def verify_bootstatus(self, entry, bootstatus): + """Verify bootstatus for entry.""" rawfiles = glob.glob("/etc/rc*.d/[SK]*%s" % (entry.get('name'))) files = [] @@ -54,9 +52,9 @@ class DebInit(Bcfg2.Client.Tools.SvcTool): continue if match.group('name') == entry.get('name'): files.append(filename) - if entry.get('status') == 'off': + if bootstatus == 'off': if files: - entry.set('current_status', 'on') + entry.set('current_bootstatus', 'on') return False else: return True @@ -72,12 +70,47 @@ class DebInit(Bcfg2.Client.Tools.SvcTool): return False return True else: - entry.set('current_status', 'off') + entry.set('current_bootstatus', 'off') return False + def VerifyService(self, entry, _): + """Verify Service status for entry.""" + entry.set('target_status', entry.get('status')) # for reporting + bootstatus = self.get_bootstatus(entry) + if bootstatus is None: + return True + current_bootstatus = self.verify_bootstatus(entry, bootstatus) + + if entry.get('status') == 'ignore': + # 'ignore' should verify + current_svcstatus = True + svcstatus = True + else: + svcstatus = self.check_service(entry) + if entry.get('status') == 'on': + if svcstatus: + current_svcstatus = True + else: + current_svcstatus = False + elif entry.get('status') == 'off': + if svcstatus: + current_svcstatus = False + else: + current_svcstatus = True + + if svcstatus: + entry.set('current_status', 'on') + else: + entry.set('current_status', 'off') + + return current_bootstatus and current_svcstatus + def InstallService(self, entry): - """Install Service for entry.""" + """Install Service entry.""" self.logger.info("Installing Service %s" % (entry.get('name'))) + bootstatus = entry.get('bootstatus') + + # check if init script exists try: os.stat('/etc/init.d/%s' % entry.get('name')) except OSError: @@ -85,20 +118,41 @@ class DebInit(Bcfg2.Client.Tools.SvcTool): entry.get('name')) return False - if entry.get('status') == 'off': - self.cmd.run("/usr/sbin/invoke-rc.d %s stop" % (entry.get('name'))) - return self.cmd.run("/usr/sbin/update-rc.d -f %s remove" % - entry.get('name')).success + if bootstatus is not None: + seqcmdrv = True + if bootstatus == 'on': + # make sure service is enabled on boot + bootcmd = '/usr/sbin/update-rc.d %s defaults' % \ + entry.get('name') + if entry.get('sequence'): + seqcmd = '/usr/sbin/update-rc.d -f %s remove' % \ + entry.get('name') + seqcmdrv = self.cmd.run(seqcmd) + start_sequence = int(entry.get('sequence')) + kill_sequence = 100 - start_sequence + bootcmd = '%s %d %d' % (bootcmd, start_sequence, + kill_sequence) + elif bootstatus == 'off': + # make sure service is disabled on boot + bootcmd = '/usr/sbin/update-rc.d -f %s remove' % \ + entry.get('name') + bootcmdrv = self.cmd.run(bootcmd) + if self.setup['servicemode'] == 'disabled': + # 'disabled' means we don't attempt to modify running svcs + return bootcmdrv and seqcmdrv + buildmode = self.setup['servicemode'] == 'build' + if (entry.get('status') == 'on' and not buildmode) and \ + entry.get('current_status') == 'off': + svccmdrv = self.start_service(entry) + elif (entry.get('status') == 'off' or buildmode) and \ + entry.get('current_status') == 'on': + svccmdrv = self.stop_service(entry) + else: + svccmdrv = True # ignore status attribute + return bootcmdrv and svccmdrv and seqcmdrv else: - command = "/usr/sbin/update-rc.d %s defaults" % (entry.get('name')) - if entry.get('sequence'): - if not self.cmd.run("/usr/sbin/update-rc.d -f %s remove" % - entry.get('name')).success: - return False - start_sequence = int(entry.get('sequence')) - kill_sequence = 100 - start_sequence - command = "%s %d %d" % (command, start_sequence, kill_sequence) - return self.cmd.run(command).success + # when bootstatus is 'None', status == 'ignore' + return True def FindExtra(self): """Find Extra Debian Service entries.""" @@ -116,6 +170,3 @@ class DebInit(Bcfg2.Client.Tools.SvcTool): # Extra service removal is nonsensical # Extra services need to be reflected in the config return - - def get_svc_command(self, service, action): - return '/usr/sbin/invoke-rc.d %s %s' % (service.get('name'), action) diff --git a/src/lib/Bcfg2/Client/Tools/POSIX/Directory.py b/src/lib/Bcfg2/Client/Tools/POSIX/Directory.py index 9d0fe05e0..675a4461a 100644 --- a/src/lib/Bcfg2/Client/Tools/POSIX/Directory.py +++ b/src/lib/Bcfg2/Client/Tools/POSIX/Directory.py @@ -36,14 +36,14 @@ class POSIXDirectory(POSIXTool): self.logger.info("POSIX: " + msg) entry.set('qtext', entry.get('qtext', '') + '\n' + msg) for extra in extras: - Bcfg2.Client.XML.SubElement(entry, 'Prune', path=extra) + Bcfg2.Client.XML.SubElement(entry, 'Prune', name=extra) except OSError: prune = True return POSIXTool.verify(self, entry, modlist) and prune def install(self, entry): - """Install device entries.""" + """Install directory entries.""" fmode = self._exists(entry) if fmode and not stat.S_ISDIR(fmode[stat.ST_MODE]): @@ -67,7 +67,7 @@ class POSIXDirectory(POSIXTool): if entry.get('prune', 'false') == 'true': for pent in entry.findall('Prune'): - pname = pent.get('path') + pname = pent.get('name') try: self.logger.debug("POSIX: Removing %s" % pname) self._remove(pent) diff --git a/src/lib/Bcfg2/Client/Tools/POSIXUsers.py b/src/lib/Bcfg2/Client/Tools/POSIXUsers.py index 99ed3c7d9..8226392f9 100644 --- a/src/lib/Bcfg2/Client/Tools/POSIXUsers.py +++ b/src/lib/Bcfg2/Client/Tools/POSIXUsers.py @@ -154,7 +154,8 @@ class POSIXUsers(Bcfg2.Client.Tools.Tool): if entry.get("current_exists", "true") == "true": # verify supplemental groups actual = [g[0] for g in self.user_supplementary_groups(entry)] - expected = [e.text for e in entry.findall("MemberOf")] + expected = [e.get("group", e.text).strip() + for e in entry.findall("MemberOf")] if set(expected) != set(actual): entry.set('qtext', "\n".join([entry.get('qtext', '')] + @@ -252,7 +253,8 @@ class POSIXUsers(Bcfg2.Client.Tools.Tool): if entry.get('uid'): cmd.extend(['-u', entry.get('uid')]) cmd.extend(['-g', entry.get('group')]) - extras = [e.text for e in entry.findall("MemberOf")] + extras = [e.get("group", e.text).strip() + for e in entry.findall("MemberOf")] if extras: cmd.extend(['-G', ",".join(extras)]) cmd.extend(['-d', entry.get('home')]) diff --git a/src/lib/Bcfg2/Client/Tools/Portage.py b/src/lib/Bcfg2/Client/Tools/Portage.py index 17e7755a9..2d8b66ce5 100644 --- a/src/lib/Bcfg2/Client/Tools/Portage.py +++ b/src/lib/Bcfg2/Client/Tools/Portage.py @@ -74,10 +74,10 @@ class Portage(Bcfg2.Client.Tools.PkgTool): self.logger.debug('Running equery check on %s' % entry.get('name')) - for line in self.cmd.run(["/usr/bin/equery", "-N", "check", - '=%s-%s' % - (entry.get('name'), - version)]).stdout.splitlines(): + for line in self.cmd.run( + ["/usr/bin/equery", "-N", "check", + '=%s-%s' % (entry.get('name'), + entry.get('version'))]).stdout.splitlines(): if '!!!' in line and line.split()[1] not in modlist: return False diff --git a/src/lib/Bcfg2/Client/Tools/RcUpdate.py b/src/lib/Bcfg2/Client/Tools/RcUpdate.py index 4b78581f7..8e9626521 100644 --- a/src/lib/Bcfg2/Client/Tools/RcUpdate.py +++ b/src/lib/Bcfg2/Client/Tools/RcUpdate.py @@ -21,21 +21,38 @@ class RcUpdate(Bcfg2.Client.Tools.SvcTool): '-s']).stdout.splitlines() if 'started' in line] + def get_default_svcs(self): + """Return a list of services in the 'default' runlevel.""" + return [line.split()[0] + for line in self.cmd.run(['/sbin/rc-update', + 'show']).stdout.splitlines() + if 'default' in line] + + def verify_bootstatus(self, entry, bootstatus): + """Verify bootstatus for entry.""" + # get a list of all started services + allsrv = self.get_default_svcs() + # set current_bootstatus attribute + if entry.get('name') in allsrv: + entry.set('current_bootstatus', 'on') + else: + entry.set('current_bootstatus', 'off') + if bootstatus == 'on': + return entry.get('name') in allsrv + else: + return entry.get('name') not in allsrv + def VerifyService(self, entry, _): """ Verify Service status for entry. Assumes we run in the "default" runlevel. """ - if entry.get('status') == 'ignore': + entry.set('target_status', entry.get('status')) # for reporting + bootstatus = self.get_bootstatus(entry) + if bootstatus is None: return True - - # get a list of all started services - allsrv = self.get_enabled_svcs() - - # check if service is enabled - result = self.cmd.run(["/sbin/rc-update", "show", "default"]).stdout - is_enabled = entry.get("name") in result + current_bootstatus = self.verify_bootstatus(entry, bootstatus) # check if init script exists try: @@ -45,39 +62,58 @@ class RcUpdate(Bcfg2.Client.Tools.SvcTool): entry.get('name')) return False - # check if service is enabled - is_running = entry.get('name') in allsrv - - if entry.get('status') == 'on' and not (is_enabled and is_running): - entry.set('current_status', 'off') - return False - - elif entry.get('status') == 'off' and (is_enabled or is_running): + if entry.get('status') == 'ignore': + # 'ignore' should verify + current_svcstatus = True + svcstatus = True + else: + svcstatus = self.check_service(entry) + if entry.get('status') == 'on': + if svcstatus: + current_svcstatus = True + else: + current_svcstatus = False + elif entry.get('status') == 'off': + if svcstatus: + current_svcstatus = False + else: + current_svcstatus = True + + if svcstatus: entry.set('current_status', 'on') - return False + else: + entry.set('current_status', 'off') - return True + return current_bootstatus and current_svcstatus def InstallService(self, entry): - """ - Install Service entry - - """ + """Install Service entry.""" self.logger.info('Installing Service %s' % entry.get('name')) - if entry.get('status') == 'on': - if entry.get('current_status') == 'off': - self.start_service(entry) - # make sure it's enabled - cmd = '/sbin/rc-update add %s default' - return self.cmd.run(cmd % entry.get('name')).success - elif entry.get('status') == 'off': - if entry.get('current_status') == 'on': - self.stop_service(entry) - # make sure it's disabled - cmd = '/sbin/rc-update del %s default' - return self.cmd.run(cmd % entry.get('name')).success - - return False + bootstatus = entry.get('bootstatus') + if bootstatus is not None: + if bootstatus == 'on': + # make sure service is enabled on boot + bootcmd = '/sbin/rc-update add %s default' + elif bootstatus == 'off': + # make sure service is disabled on boot + bootcmd = '/sbin/rc-update del %s default' + bootcmdrv = self.cmd.run(bootcmd % entry.get('name')).success + if self.setup['servicemode'] == 'disabled': + # 'disabled' means we don't attempt to modify running svcs + return bootcmdrv + buildmode = self.setup['servicemode'] == 'build' + if (entry.get('status') == 'on' and not buildmode) and \ + entry.get('current_status') == 'off': + svccmdrv = self.start_service(entry) + elif (entry.get('status') == 'off' or buildmode) and \ + entry.get('current_status') == 'on': + svccmdrv = self.stop_service(entry) + else: + svccmdrv = True # ignore status attribute + return bootcmdrv and svccmdrv + else: + # when bootstatus is 'None', status == 'ignore' + return True def FindExtra(self): """Locate extra rc-update services.""" diff --git a/src/lib/Bcfg2/Client/Tools/Systemd.py b/src/lib/Bcfg2/Client/Tools/Systemd.py index 027d91c71..20a172d3d 100644 --- a/src/lib/Bcfg2/Client/Tools/Systemd.py +++ b/src/lib/Bcfg2/Client/Tools/Systemd.py @@ -13,6 +13,8 @@ class Systemd(Bcfg2.Client.Tools.SvcTool): __handles__ = [('Service', 'systemd')] __req__ = {'Service': ['name', 'status']} + conflicts = ['Chkconfig'] + def get_svc_command(self, service, action): return "/bin/systemctl %s %s.service" % (action, service.get('name')) diff --git a/src/lib/Bcfg2/Client/Tools/__init__.py b/src/lib/Bcfg2/Client/Tools/__init__.py index c5a5ee4d6..11fe55bd6 100644 --- a/src/lib/Bcfg2/Client/Tools/__init__.py +++ b/src/lib/Bcfg2/Client/Tools/__init__.py @@ -519,6 +519,22 @@ class SvcTool(Tool): """ return '/etc/init.d/%s %s' % (service.get('name'), action) + def get_bootstatus(self, service): + """ Return the bootstatus attribute if it exists. + + :param service: The service entry + :type service: lxml.etree._Element + :returns: string or None - Value of bootstatus if it exists. If + bootstatus is unspecified and status is not *ignore*, + return value of status. If bootstatus is unspecified + and status is *ignore*, return None. + """ + if service.get('bootstatus') is not None: + return service.get('bootstatus') + elif service.get('status') != 'ignore': + return service.get('status') + return None + def start_service(self, service): """ Start a service. diff --git a/src/lib/Bcfg2/Client/__init__.py b/src/lib/Bcfg2/Client/__init__.py index e40ef750b..3bc261f2f 100644 --- a/src/lib/Bcfg2/Client/__init__.py +++ b/src/lib/Bcfg2/Client/__init__.py @@ -19,7 +19,7 @@ def prompt(msg): while len(select.select([sys.stdin.fileno()], [], [], 0.0)[0]) > 0: os.read(sys.stdin.fileno(), 4096) try: - ans = input(msg.encode(sys.stdout.encoding, 'replace')) + ans = input(msg) return ans in ['y', 'Y'] except EOFError: # python 2.4.3 on CentOS doesn't like ^C for some reason |