"""Debian Init Support for Bcfg2""" import glob import os import re import Bcfg2.Client.Tools # Debian squeeze and beyond uses a dependecy based boot sequence DEBIAN_OLD_STYLE_BOOT_SEQUENCE = ('etch', '4.0', 'lenny') class DebInit(Bcfg2.Client.Tools.SvcTool): """Debian Service Support for Bcfg2.""" name = 'DebInit' __execs__ = ['/usr/sbin/update-rc.d', '/usr/sbin/invoke-rc.d'] __handles__ = [('Service', 'deb')] __req__ = {'Service': ['name', 'status']} svcre = \ re.compile(r'/etc/.*/(?P[SK])(?P\d+)(?P\S+)') 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 = [] try: deb_version = open('/etc/debian_version').read().split('/', 1)[0] except IOError: deb_version = 'unknown' if entry.get('sequence'): if (deb_version in DEBIAN_OLD_STYLE_BOOT_SEQUENCE or deb_version.startswith('5') or os.path.exists('/etc/init.d/.legacy-bootordering')): start_sequence = int(entry.get('sequence')) kill_sequence = 100 - start_sequence else: start_sequence = None self.logger.warning("Your debian version boot sequence is " "dependency based \"sequence\" attribute " "will be ignored.") else: start_sequence = None for filename in rawfiles: match = self.svcre.match(filename) if not match: self.logger.error("Failed to match file: %s" % filename) continue if match.group('name') == entry.get('name'): files.append(filename) if bootstatus == 'off': if files: entry.set('current_bootstatus', 'on') return False else: return True elif files: if start_sequence: for filename in files: match = self.svcre.match(filename) file_sequence = int(match.group('sequence')) if ((match.group('action') == 'S' and file_sequence != start_sequence) or (match.group('action') == 'K' and file_sequence != kill_sequence)): return False return True else: 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 entry.""" self.logger.info("Installing Service %s" % (entry.get('name'))) bootstatus = self.get_bootstatus(entry) # check if init script exists try: os.stat('/etc/init.d/%s' % entry.get('name')) except OSError: self.logger.debug("Init script for service %s does not exist" % entry.get('name')) return False 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: # when bootstatus is 'None', status == 'ignore' return True def FindExtra(self): """Find Extra Debian Service entries.""" specified = [entry.get('name') for entry in self.getSupportedEntries()] extra = set() for fname in glob.glob("/etc/rc[12345].d/S*"): name = self.svcre.match(fname).group('name') if name not in specified: extra.add(name) return [Bcfg2.Client.XML.Element('Service', name=name, type='deb') for name in list(extra)] def Remove(self, _): """Remove extra service entries.""" # Extra service removal is nonsensical # Extra services need to be reflected in the config return