From 0d13c2b0c40e63672bae4ef18eb945d15a85bb50 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Tue, 21 May 2013 09:43:42 -0400 Subject: Packages: don't cache package collections with no sources --- src/lib/Bcfg2/Server/Plugins/Packages/__init__.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/__init__.py b/src/lib/Bcfg2/Server/Plugins/Packages/__init__.py index d5773de97..f82b8a392 100644 --- a/src/lib/Bcfg2/Server/Plugins/Packages/__init__.py +++ b/src/lib/Bcfg2/Server/Plugins/Packages/__init__.py @@ -527,8 +527,9 @@ class Packages(Bcfg2.Server.Plugin.Plugin, collection = cclass(metadata, relevant, self.cachepath, self.data, self.core.fam, debug=self.debug_flag) ckey = collection.cachekey - self.clients[metadata.hostname] = ckey - self.collections[ckey] = collection + if cclass != Collection: + self.clients[metadata.hostname] = ckey + self.collections[ckey] = collection return collection def get_additional_data(self, metadata): -- cgit v1.2.3-1-g7c22 From f55238772edf411cb101f4b179c357fffa665345 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Tue, 21 May 2013 13:50:49 -0400 Subject: FileProbes: made client probe compatible with bcfg2 1.2 --- src/lib/Bcfg2/Server/Plugins/FileProbes.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/lib/Bcfg2/Server/Plugins/FileProbes.py b/src/lib/Bcfg2/Server/Plugins/FileProbes.py index d816192aa..8e074118f 100644 --- a/src/lib/Bcfg2/Server/Plugins/FileProbes.py +++ b/src/lib/Bcfg2/Server/Plugins/FileProbes.py @@ -24,7 +24,11 @@ import sys import pwd import grp import Bcfg2.Client.XML -from Bcfg2.Compat import b64encode, oct_mode +try: + from Bcfg2.Compat import b64encode, oct_mode +except ImportError: + from base64 import b64encode + oct_mode = oct path = "%s" -- cgit v1.2.3-1-g7c22 From ca43145539ec82623c9fd8f62a1e05f261cdf215 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Tue, 21 May 2013 16:04:24 -0400 Subject: POSIX: fix directory pruning --- src/lib/Bcfg2/Client/Tools/POSIX/Directory.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/lib/Bcfg2/Client/Tools/POSIX/Directory.py b/src/lib/Bcfg2/Client/Tools/POSIX/Directory.py index 9d0fe05e0..d1f451c34 100644 --- a/src/lib/Bcfg2/Client/Tools/POSIX/Directory.py +++ b/src/lib/Bcfg2/Client/Tools/POSIX/Directory.py @@ -36,7 +36,7 @@ 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 @@ -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) -- cgit v1.2.3-1-g7c22 From bb8b63c8f75ebe53b60bcb6680602a56e975973b Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Tue, 21 May 2013 16:04:35 -0400 Subject: POSIX: fix docstring --- src/lib/Bcfg2/Client/Tools/POSIX/Directory.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/lib/Bcfg2/Client/Tools/POSIX/Directory.py b/src/lib/Bcfg2/Client/Tools/POSIX/Directory.py index d1f451c34..675a4461a 100644 --- a/src/lib/Bcfg2/Client/Tools/POSIX/Directory.py +++ b/src/lib/Bcfg2/Client/Tools/POSIX/Directory.py @@ -43,7 +43,7 @@ class POSIXDirectory(POSIXTool): 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]): -- cgit v1.2.3-1-g7c22 From 7bfe2b81d22734e559f1335e35ffd720db1ccf0e Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Tue, 21 May 2013 16:20:02 -0400 Subject: Yum: prevent traceback with empty repository --- src/lib/Bcfg2/Server/Plugins/Packages/Yum.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py b/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py index 7438c633b..bb7caab0d 100644 --- a/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py +++ b/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py @@ -1120,9 +1120,9 @@ class YumSource(Source): self.packages['global'] = copy.deepcopy(sdata.pop()) except IndexError: self.logger.error("Packages: No packages in repo") + self.packages['global'] = set() while sdata: - self.packages['global'] = \ - self.packages['global'].intersection(sdata.pop()) + self.packages['global'].update(sdata.pop()) for key in self.packages: if key == 'global': -- cgit v1.2.3-1-g7c22 From b0877561d20cdb7a21c5761428d9643e89f53773 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Wed, 22 May 2013 11:30:20 -0400 Subject: tools: make migrate_info.py migrate "perms" (http://trac.mcs.anl.gov/projects/bcfg2/ticket/1150) --- src/lib/Bcfg2/Server/Plugin/helpers.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/lib/Bcfg2/Server/Plugin/helpers.py b/src/lib/Bcfg2/Server/Plugin/helpers.py index b14968d77..81dc1d736 100644 --- a/src/lib/Bcfg2/Server/Plugin/helpers.py +++ b/src/lib/Bcfg2/Server/Plugin/helpers.py @@ -41,15 +41,15 @@ del DEFAULT_FILE_METADATA['configfile'] LOGGER = logging.getLogger(__name__) #: a compiled regular expression for parsing info and :info files -INFO_REGEX = re.compile(r'owner:(\s)*(?P\S+)|' + - r'group:(\s)*(?P\S+)|' + - r'mode:(\s)*(?P\w+)|' + - r'secontext:(\s)*(?P\S+)|' + - r'paranoid:(\s)*(?P\S+)|' + - r'sensitive:(\s)*(?P\S+)|' + - r'encoding:(\s)*(?P\S+)|' + - r'important:(\s)*(?P\S+)|' + - r'mtime:(\s)*(?P\w+)|') +INFO_REGEX = re.compile(r'owner:\s*(?P\S+)|' + + r'group:\s*(?P\S+)|' + + r'mode:\s*(?P\w+)|' + + r'secontext:\s*(?P\S+)|' + + r'paranoid:\s*(?P\S+)|' + + r'sensitive:\s*(?P\S+)|' + + r'encoding:\s*(?P\S+)|' + + r'important:\s*(?P\S+)|' + + r'mtime:\s*(?P\w+)') def bind_info(entry, metadata, infoxml=None, default=DEFAULT_FILE_METADATA): -- cgit v1.2.3-1-g7c22 From 4133bceb4153a6674ac5cb9a182942537c1dde45 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Thu, 23 May 2013 08:28:56 -0400 Subject: Proxy: handle BadStatusLine errors gracefully --- src/lib/Bcfg2/Proxy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/lib/Bcfg2/Proxy.py b/src/lib/Bcfg2/Proxy.py index 9246c0f87..f6db66a93 100644 --- a/src/lib/Bcfg2/Proxy.py +++ b/src/lib/Bcfg2/Proxy.py @@ -314,7 +314,7 @@ class XMLRPCTransport(xmlrpclib.Transport): errcode = response.status errmsg = response.reason headers = response.msg - except (socket.error, SSL_ERROR): + except (socket.error, SSL_ERROR, httplib.BadStatusLine): err = sys.exc_info()[1] raise ProxyError(xmlrpclib.ProtocolError(host + handler, 408, -- cgit v1.2.3-1-g7c22 From ae765a2e2d82170205a27371a07e1a80aa903fc9 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Thu, 23 May 2013 08:54:18 -0400 Subject: fixed pylint test --- src/sbin/bcfg2-server | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/sbin/bcfg2-server b/src/sbin/bcfg2-server index 21f7842ec..b910eeb64 100755 --- a/src/sbin/bcfg2-server +++ b/src/sbin/bcfg2-server @@ -37,7 +37,8 @@ def main(): coremodule = backends[setup['backend']] try: - Core = getattr(__import__("Bcfg2.Server.%s" % coremodule).Server, + Core = getattr( # pylint: disable=C0103 + __import__("Bcfg2.Server.%s" % coremodule).Server, coremodule).Core except ImportError: err = sys.exc_info()[1] -- cgit v1.2.3-1-g7c22 From 7145c19965cdf593739541660b57eb68944661e4 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Thu, 23 May 2013 09:25:51 -0400 Subject: really fixed pylint issues with cbcfg2-server --- src/sbin/bcfg2-server | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/sbin/bcfg2-server b/src/sbin/bcfg2-server index b910eeb64..4c4a71fa7 100755 --- a/src/sbin/bcfg2-server +++ b/src/sbin/bcfg2-server @@ -37,9 +37,8 @@ def main(): coremodule = backends[setup['backend']] try: - Core = getattr( # pylint: disable=C0103 - __import__("Bcfg2.Server.%s" % coremodule).Server, - coremodule).Core + corecls = getattr(__import__("Bcfg2.Server.%s" % coremodule).Server, + coremodule).Core except ImportError: err = sys.exc_info()[1] print("Unable to import %s server core: %s" % (setup['backend'], err)) @@ -50,7 +49,7 @@ def main(): raise try: - core = Core(setup) + core = corecls(setup) core.run() except CoreInitError: msg = sys.exc_info()[1] -- cgit v1.2.3-1-g7c22 From 713748923e3db2d2cb56e489077e5467449e8860 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Thu, 23 May 2013 16:42:49 -0400 Subject: Options: fixed typo in option --- src/lib/Bcfg2/Options.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/lib/Bcfg2/Options.py b/src/lib/Bcfg2/Options.py index fd7c4421a..243c4ed2a 100644 --- a/src/lib/Bcfg2/Options.py +++ b/src/lib/Bcfg2/Options.py @@ -579,7 +579,7 @@ SERVER_PASSWORD = \ SERVER_PROTOCOL = \ Option('Server Protocol', default='xmlrpc/ssl', - cf=('communication', 'procotol')) + cf=('communication', 'protocol')) SERVER_BACKEND = \ Option('Server Backend', default='best', -- cgit v1.2.3-1-g7c22 From 9ca707512918f6befe52001602ffccb9ab513fb6 Mon Sep 17 00:00:00 2001 From: Jake Davis Date: Fri, 24 May 2013 09:40:35 -0400 Subject: Fix for null target_status in Reporting_sericeentry --- src/lib/Bcfg2/Client/Tools/Chkconfig.py | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/lib/Bcfg2/Client/Tools/Chkconfig.py b/src/lib/Bcfg2/Client/Tools/Chkconfig.py index c3dcf7796..1fce5515b 100644 --- a/src/lib/Bcfg2/Client/Tools/Chkconfig.py +++ b/src/lib/Bcfg2/Client/Tools/Chkconfig.py @@ -21,6 +21,7 @@ class Chkconfig(Bcfg2.Client.Tools.SvcTool): def VerifyService(self, entry, _): """Verify Service status for entry.""" + entry.set('target_status', entry.get('status')) if entry.get('status') == 'ignore': return True -- cgit v1.2.3-1-g7c22 From 6fffddf1cc3e73bf831fb3bbe36c928d1ebb8c77 Mon Sep 17 00:00:00 2001 From: Michael Fenn Date: Fri, 24 May 2013 12:11:55 -0400 Subject: Cfg: Handle bogus created events as changed It is possible for the FAM (gamin in particular) to send a created event for a file that already exists if the file is updated in a particular way. I suppose that the event is technically correct since a new inode really was created, but the file is only changed from bcfg2's point of view. For instance, the "atomic" copy-to-temp-then-move-over-top method that rsync uses will expose this behavior. Example: rsync -a --temp-dir=/var/tmp --delete-after \ --exclude Packages/cache --exclude Packages/keys \ --exclude Reporting/DirectStore --exclude probed.xml \ /var/lib/bcfg2/ $OTHERSERVER:/var/lib/bcfg2 --- src/lib/Bcfg2/Server/Plugins/Cfg/__init__.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/lib/Bcfg2/Server/Plugins/Cfg/__init__.py b/src/lib/Bcfg2/Server/Plugins/Cfg/__init__.py index ffe93c25b..c6ac9d8dc 100644 --- a/src/lib/Bcfg2/Server/Plugins/Cfg/__init__.py +++ b/src/lib/Bcfg2/Server/Plugins/Cfg/__init__.py @@ -520,7 +520,9 @@ class CfgEntrySet(Bcfg2.Server.Plugin.EntrySet, return elif hdlr.ignore(event, basename=self.path): return - elif action == 'changed': + # we only get here if event.filename in self.entries, so handle + # created event like changed + elif action == 'changed' or action == 'created': self.entries[event.filename].handle_event(event) return elif action == 'deleted': -- cgit v1.2.3-1-g7c22 From ad8ce7c23818f76c4aed5646fe3a4bbbcfa15f64 Mon Sep 17 00:00:00 2001 From: Jake Davis Date: Fri, 24 May 2013 15:45:13 -0400 Subject: Another fix for null target_status in Reporting_sericeentry. This one covers Extra entries. --- src/lib/Bcfg2/Reporting/Storage/DjangoORM.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/lib/Bcfg2/Reporting/Storage/DjangoORM.py b/src/lib/Bcfg2/Reporting/Storage/DjangoORM.py index 3b2c0ccfa..aea5e9d4b 100644 --- a/src/lib/Bcfg2/Reporting/Storage/DjangoORM.py +++ b/src/lib/Bcfg2/Reporting/Storage/DjangoORM.py @@ -197,7 +197,8 @@ class DjangoORM(StorageBase): def _import_Service(self, entry, state): return self._import_default(entry, state, defaults=dict(status='', - current_status=''), + current_status='', + target_status=''), mapping=dict(status='target_status')) def _import_SEBoolean(self, entry, state): -- cgit v1.2.3-1-g7c22 From e7fece63c1afc2c45b0627c7980b476a56eefe33 Mon Sep 17 00:00:00 2001 From: Sol Jerome Date: Wed, 29 May 2013 08:40:26 -0500 Subject: Reporting: Fix traceback Signed-off-by: Sol Jerome --- src/lib/Bcfg2/Reporting/models.py | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/lib/Bcfg2/Reporting/models.py b/src/lib/Bcfg2/Reporting/models.py index 28c38e741..598e1c6ec 100644 --- a/src/lib/Bcfg2/Reporting/models.py +++ b/src/lib/Bcfg2/Reporting/models.py @@ -26,6 +26,8 @@ TYPE_CHOICES = ( (TYPE_EXTRA, 'Extra'), ) +_our_backend = None + def convert_entry_type_to_id(type_name): """Convert a entry type to its entry id""" @@ -49,7 +51,6 @@ def hash_entry(entry_dict): return hash(cPickle.dumps(dataset)) -_our_backend = None def _quote(value): """ Quote a string to use as a table name or column @@ -59,7 +60,10 @@ def _quote(value): """ global _our_backend if not _our_backend: - _our_backend = backend.DatabaseOperations(connection) + try: + _our_backend = backend.DatabaseOperations(connection) + except TypeError: + _our_backend = backend.DatabaseOperations() return _our_backend.quote_name(value) @@ -113,7 +117,6 @@ class InteractionManager(models.Manager): pass return [] - def recent(self, maxdate=None): """ Returns the most recent interactions for clients as of a date @@ -133,7 +136,7 @@ class Interaction(models.Model): timestamp = models.DateTimeField(db_index=True) # Timestamp for this record state = models.CharField(max_length=32) # good/bad/modified/etc repo_rev_code = models.CharField(max_length=64) # repo revision at time of interaction - server = models.CharField(max_length=256) # Name of the server used for the interaction + server = models.CharField(max_length=256) # server used for interaction good_count = models.IntegerField() # of good config-items total_count = models.IntegerField() # of total config-items bad_count = models.IntegerField(default=0) @@ -230,7 +233,7 @@ class Interaction(models.Model): rv = [] for entry in self.entry_types: if entry == 'failures': - continue + continue rv.extend(getattr(self, entry).filter(state=TYPE_BAD)) return rv @@ -238,7 +241,7 @@ class Interaction(models.Model): rv = [] for entry in self.entry_types: if entry == 'failures': - continue + continue rv.extend(getattr(self, entry).filter(state=TYPE_MODIFIED)) return rv @@ -246,7 +249,7 @@ class Interaction(models.Model): rv = [] for entry in self.entry_types: if entry == 'failures': - continue + continue rv.extend(getattr(self, entry).filter(state=TYPE_EXTRA)) return rv @@ -258,7 +261,8 @@ class Interaction(models.Model): class Performance(models.Model): """Object representing performance data for any interaction.""" - interaction = models.ForeignKey(Interaction, related_name="performance_items") + interaction = models.ForeignKey(Interaction, + related_name="performance_items") metric = models.CharField(max_length=128) value = models.DecimalField(max_digits=32, decimal_places=16) @@ -291,11 +295,11 @@ class Group(models.Model): class Meta: ordering = ('name',) - @staticmethod def prune_orphans(): '''Prune unused groups''' - Group.objects.filter(interaction__isnull=True, group__isnull=True).delete() + Group.objects.filter(interaction__isnull=True, + group__isnull=True).delete() class Bundle(models.Model): @@ -313,11 +317,11 @@ class Bundle(models.Model): class Meta: ordering = ('name',) - @staticmethod def prune_orphans(): '''Prune unused bundles''' - Bundle.objects.filter(interaction__isnull=True, group__isnull=True).delete() + Bundle.objects.filter(interaction__isnull=True, + group__isnull=True).delete() # new interaction models @@ -420,7 +424,7 @@ class BaseEntry(models.Model): def prune_orphans(cls): '''Remove unused entries''' # yeat another sqlite hack - cls_orphans = [x['id'] \ + cls_orphans = [x['id'] for x in cls.objects.filter(interaction__isnull=True).values("id")] i = 0 while i < len(cls_orphans): @@ -695,7 +699,7 @@ class PathEntry(SuccessEntry): acls = models.ManyToManyField(FileAcl) detail_type = models.IntegerField(default=0, - choices=DETAIL_CHOICES) + choices=DETAIL_CHOICES) details = models.TextField(default='') ENTRY_TYPE = r"Path" -- cgit v1.2.3-1-g7c22 From eadc444fd49644c02241ad18acedede62747010f Mon Sep 17 00:00:00 2001 From: Sol Jerome Date: Sun, 2 Jun 2013 08:46:08 -0500 Subject: bcfg2-info: Handle IOErrors Signed-off-by: Sol Jerome --- src/sbin/bcfg2-info | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/sbin/bcfg2-info b/src/sbin/bcfg2-info index 6aafd24d1..4e71ba35a 100755 --- a/src/sbin/bcfg2-info +++ b/src/sbin/bcfg2-info @@ -231,10 +231,14 @@ class InfoCore(cmd.Cmd, Bcfg2.Server.Core.BaseCore): print("Refusing to write files outside of /tmp without -f " "option") return - lxml.etree.ElementTree(self.BuildConfiguration(client)).write( - ofile, - encoding='UTF-8', xml_declaration=True, - pretty_print=True) + try: + lxml.etree.ElementTree(self.BuildConfiguration(client)).write( + ofile, + encoding='UTF-8', xml_declaration=True, + pretty_print=True) + except IOError: + err = sys.exc_info()[1] + print("Failed to write File %s: %s" % (ofile, err)) else: print(self._get_usage(self.do_build)) -- cgit v1.2.3-1-g7c22 From 6e8031680422a238fd8ea9fbc5ea04f2fd1e2a57 Mon Sep 17 00:00:00 2001 From: Sol Jerome Date: Sun, 2 Jun 2013 08:49:18 -0500 Subject: Services: Add new bootstatus attribute This new attribute allows the specification of a boot-time status separately from the current 'status' attribute. This allows for more fine-grained control over e.g. services that are really just boot scripts. Signed-off-by: Sol Jerome --- src/lib/Bcfg2/Client/Tools/Chkconfig.py | 99 ++++++++++++++++++----------- src/lib/Bcfg2/Client/Tools/DebInit.py | 97 +++++++++++++++++++++-------- src/lib/Bcfg2/Client/Tools/RcUpdate.py | 106 +++++++++++++++++++++----------- src/lib/Bcfg2/Client/Tools/__init__.py | 16 +++++ 4 files changed, 223 insertions(+), 95 deletions(-) (limited to 'src') diff --git a/src/lib/Bcfg2/Client/Tools/Chkconfig.py b/src/lib/Bcfg2/Client/Tools/Chkconfig.py index 1fce5515b..0f5f32302 100644 --- a/src/lib/Bcfg2/Client/Tools/Chkconfig.py +++ b/src/lib/Bcfg2/Client/Tools/Chkconfig.py @@ -19,26 +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.""" - entry.set('target_status', entry.get('status')) - 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: @@ -47,40 +43,73 @@ 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') == 'on': - entry.set('current_status', 'off') + svcstatus = self.check_service(entry) + if entry.get('status') == 'on': + if svcstatus: + current_srvstatus = True + else: + current_srvstatus = False + elif entry.get('status') == 'off': + if svcstatus: + current_srvstatus = False else: - entry.set('current_status', 'on') - return status + current_srvstatus = True + else: + # 'ignore' should verify + current_srvstatus = True + + if svcstatus: + entry.set('current_status', 'on') + else: + entry.set('current_status', 'off') + + return current_bootstatus and current_srvstatus 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' or - self.setup["servicemode"] == "build"): - rv &= self.cmd.run((rcmd + " --level 0123456") % - (entry.get('name'), - entry.get('status'))).success - if entry.get("current_status") == "on" and \ - self.setup["servicemode"] != "disabled": - 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" and \ - self.setup["servicemode"] != "disabled": - 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..116d4f8b0 100644 --- a/src/lib/Bcfg2/Client/Tools/DebInit.py +++ b/src/lib/Bcfg2/Client/Tools/DebInit.py @@ -18,13 +18,8 @@ class DebInit(Bcfg2.Client.Tools.SvcTool): svcre = \ re.compile(r'/etc/.*/(?P[SK])(?P\d+)(?P\S+)') - # implement entry (Verify|Install) ops - 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.""" rawfiles = glob.glob("/etc/rc*.d/[SK]*%s" % (entry.get('name'))) files = [] @@ -54,9 +49,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 +67,45 @@ 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) + + svcstatus = self.check_service(entry) + if entry.get('status') == 'on': + if svcstatus: + current_srvstatus = True + else: + current_srvstatus = False + elif entry.get('status') == 'off': + if svcstatus: + current_srvstatus = False + else: + current_srvstatus = True + else: + # 'ignore' should verify + current_srvstatus = True + + if svcstatus: + entry.set('current_status', 'on') + else: + entry.set('current_status', 'off') + + return current_bootstatus and current_srvstatus + 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 +113,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.""" diff --git a/src/lib/Bcfg2/Client/Tools/RcUpdate.py b/src/lib/Bcfg2/Client/Tools/RcUpdate.py index 4b78581f7..d6329256e 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,56 @@ 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): + svcstatus = self.check_service(entry) + if entry.get('status') == 'on': + if svcstatus: + current_srvstatus = True + else: + current_srvstatus = False + elif entry.get('status') == 'off': + if svcstatus: + current_srvstatus = False + else: + current_srvstatus = True + else: + # 'ignore' should verify + current_srvstatus = True + + if svcstatus: entry.set('current_status', 'on') - return False + else: + entry.set('current_status', 'off') - return True + return current_bootstatus and current_srvstatus 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/__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. -- cgit v1.2.3-1-g7c22