diff options
Diffstat (limited to 'src/lib/Bcfg2')
-rw-r--r-- | src/lib/Bcfg2/Client/Client.py | 1 | ||||
-rw-r--r-- | src/lib/Bcfg2/Client/Tools/APT.py | 9 | ||||
-rw-r--r-- | src/lib/Bcfg2/Client/Tools/Portage.py | 3 | ||||
-rw-r--r-- | src/lib/Bcfg2/Client/Tools/RcUpdate.py | 12 | ||||
-rw-r--r-- | src/lib/Bcfg2/Client/Tools/__init__.py | 12 | ||||
-rw-r--r-- | src/lib/Bcfg2/Logger.py | 15 | ||||
-rw-r--r-- | src/lib/Bcfg2/Reporting/Transport/LocalFilesystem.py | 6 | ||||
-rw-r--r-- | src/lib/Bcfg2/Server/Core.py | 7 | ||||
-rw-r--r-- | src/lib/Bcfg2/Server/Plugin/helpers.py | 1 | ||||
-rw-r--r-- | src/lib/Bcfg2/Server/Plugins/Metadata.py | 115 | ||||
-rw-r--r-- | src/lib/Bcfg2/Utils.py | 14 |
11 files changed, 156 insertions, 39 deletions
diff --git a/src/lib/Bcfg2/Client/Client.py b/src/lib/Bcfg2/Client/Client.py index 88f3bd6ef..2df0b11cd 100644 --- a/src/lib/Bcfg2/Client/Client.py +++ b/src/lib/Bcfg2/Client/Client.py @@ -105,6 +105,7 @@ class Client(object): self._probe_failure(name, "Return value %s" % rv) self.logger.info("Probe %s has result:" % name) self.logger.info(rv.stdout) + ret.text = rv.stdout finally: os.unlink(scriptname) except SystemExit: diff --git a/src/lib/Bcfg2/Client/Tools/APT.py b/src/lib/Bcfg2/Client/Tools/APT.py index 0cdefa613..39816403a 100644 --- a/src/lib/Bcfg2/Client/Tools/APT.py +++ b/src/lib/Bcfg2/Client/Tools/APT.py @@ -228,8 +228,13 @@ class APT(Bcfg2.Client.Tools.Tool): continue if pkg.get('version') in ['auto', 'any']: if self._newapi: - ipkgs.append("%s=%s" % (pkg.get('name'), - self.pkg_cache[pkg.get('name')].candidate.version)) + try: + ipkgs.append("%s=%s" % (pkg.get('name'), + self.pkg_cache[pkg.get('name')].candidate.version)) + except AttributeError: + self.logger.error("Failed to find %s in apt package cache" % + pkg.get('name')) + continue else: ipkgs.append("%s=%s" % (pkg.get('name'), self.pkg_cache[pkg.get('name')].candidateVersion)) diff --git a/src/lib/Bcfg2/Client/Tools/Portage.py b/src/lib/Bcfg2/Client/Tools/Portage.py index 6cbcff2e0..6b38d7dec 100644 --- a/src/lib/Bcfg2/Client/Tools/Portage.py +++ b/src/lib/Bcfg2/Client/Tools/Portage.py @@ -37,7 +37,8 @@ class Portage(Bcfg2.Client.Tools.PkgTool): return self.logger.info('Getting list of installed packages') self.installed = {} - for pkg in self.cmd.run("equery -q list '*'").stdout.splitlines(): + for pkg in self.cmd.run(["equery", "-q", + "list", "*"]).stdout.splitlines(): if self._pkg_pattern.match(pkg): name = self._pkg_pattern.match(pkg).group(1) version = self._pkg_pattern.match(pkg).group(2) diff --git a/src/lib/Bcfg2/Client/Tools/RcUpdate.py b/src/lib/Bcfg2/Client/Tools/RcUpdate.py index 2e58f2564..552b27842 100644 --- a/src/lib/Bcfg2/Client/Tools/RcUpdate.py +++ b/src/lib/Bcfg2/Client/Tools/RcUpdate.py @@ -22,8 +22,8 @@ class RcUpdate(Bcfg2.Client.Tools.SvcTool): return True # check if service is enabled - cmd = '/sbin/rc-update show default | grep %s' - is_enabled = self.cmd.run(cmd % entry.get('name')).success + result = self.cmd.run(["/sbin/rc-update", "show", "default"]) + is_enabled = entry.get("name") in result.stdout # check if init script exists try: @@ -34,8 +34,8 @@ class RcUpdate(Bcfg2.Client.Tools.SvcTool): return False # check if service is enabled - cmd = '/etc/init.d/%s status | grep started' - is_running = self.cmd.run(cmd % entry.attrib['name']).success + result = self.cmd.run(self.get_svc_command(entry, "status")) + is_running = "started" in result.stdout if entry.get('status') == 'on' and not (is_enabled and is_running): entry.set('current_status', 'off') @@ -70,9 +70,9 @@ class RcUpdate(Bcfg2.Client.Tools.SvcTool): def FindExtra(self): """Locate extra rc-update services.""" - cmd = '/bin/rc-status -s' allsrv = [line.split()[0] - for line in self.cmd.run(cmd).stdout.splitlines() + for line in self.cmd.run(['/bin/rc-status', + '-s']).stdout.splitlines() if 'started' in line] self.logger.debug('Found active services:') self.logger.debug(allsrv) diff --git a/src/lib/Bcfg2/Client/Tools/__init__.py b/src/lib/Bcfg2/Client/Tools/__init__.py index 27ca92472..c5a5ee4d6 100644 --- a/src/lib/Bcfg2/Client/Tools/__init__.py +++ b/src/lib/Bcfg2/Client/Tools/__init__.py @@ -524,8 +524,8 @@ class SvcTool(Tool): :param service: The service entry to modify :type service: lxml.etree._Element - :returns: tuple - The return value from - :class:`Bcfg2.Client.Tools.Executor.run` + :returns: Bcfg2.Utils.ExecutorResult - The return value from + :class:`Bcfg2.Utils.Executor.run` """ self.logger.debug('Starting service %s' % service.get('name')) return self.cmd.run(self.get_svc_command(service, 'start')) @@ -535,8 +535,8 @@ class SvcTool(Tool): :param service: The service entry to modify :type service: lxml.etree._Element - :returns: tuple - The return value from - :class:`Bcfg2.Client.Tools.Executor.run` + :returns: Bcfg2.Utils.ExecutorResult - The return value from + :class:`Bcfg2.Utils.Executor.run` """ self.logger.debug('Stopping service %s' % service.get('name')) return self.cmd.run(self.get_svc_command(service, 'stop')) @@ -546,8 +546,8 @@ class SvcTool(Tool): :param service: The service entry to modify :type service: lxml.etree._Element - :returns: tuple - The return value from - :class:`Bcfg2.Client.Tools.Executor.run` + :returns: Bcfg2.Utils.ExecutorResult - The return value from + :class:`Bcfg2.Utils.Executor.run` """ self.logger.debug('Restarting service %s' % service.get('name')) restart_target = service.get('target', 'restart') diff --git a/src/lib/Bcfg2/Logger.py b/src/lib/Bcfg2/Logger.py index 8f7bb14f8..5bbc9ff96 100644 --- a/src/lib/Bcfg2/Logger.py +++ b/src/lib/Bcfg2/Logger.py @@ -143,7 +143,10 @@ def add_console_handler(level=logging.DEBUG): console.setLevel(level) # tell the handler to use this format console.setFormatter(TermiosFormatter()) - console.set_name("console") + try: + console.set_name("console") + except AttributeError: + console.name = "console" logging.root.addHandler(console) @@ -158,7 +161,10 @@ def add_syslog_handler(procname, syslog_facility, level=logging.DEBUG): syslog = FragmentingSysLogHandler(procname, ('localhost', 514), syslog_facility) - syslog.set_name("syslog") + try: + syslog.set_name("syslog") + except AttributeError: + syslog.name = "syslog" syslog.setLevel(level) syslog.setFormatter( logging.Formatter('%(name)s[%(process)d]: %(message)s')) @@ -172,7 +178,10 @@ def add_syslog_handler(procname, syslog_facility, level=logging.DEBUG): def add_file_handler(to_file, level=logging.DEBUG): """Add a logging handler that logs to to_file.""" filelog = logging.FileHandler(to_file) - filelog.set_name("file") + try: + filelog.set_name("file") + except AttributeError: + filelog.name = "file" filelog.setLevel(level) filelog.setFormatter( logging.Formatter('%(asctime)s %(name)s[%(process)d]: %(message)s')) diff --git a/src/lib/Bcfg2/Reporting/Transport/LocalFilesystem.py b/src/lib/Bcfg2/Reporting/Transport/LocalFilesystem.py index 30ea39263..0a0f032e5 100644 --- a/src/lib/Bcfg2/Reporting/Transport/LocalFilesystem.py +++ b/src/lib/Bcfg2/Reporting/Transport/LocalFilesystem.py @@ -36,7 +36,8 @@ class LocalFilesystem(TransportBase): def set_debug(self, debug): rv = TransportBase.set_debug(self, debug) - self.fmon.set_debug(debug) + if self.fmon is not None: + self.fmon.set_debug(debug) return rv def start_monitor(self, collector): @@ -48,7 +49,8 @@ class LocalFilesystem(TransportBase): self.logger.error("File monitor driver %s not available; " "forcing to default" % setup['filemonitor']) fmon = Bcfg2.Server.FileMonitor.available['default'] - + if self.debug_flag: + self.fmon.set_debug(self.debug_flag) try: self.fmon = fmon(debug=self.debug_flag) self.logger.info("Using the %s file monitor" % diff --git a/src/lib/Bcfg2/Server/Core.py b/src/lib/Bcfg2/Server/Core.py index 06dfe7f25..382f11e50 100644 --- a/src/lib/Bcfg2/Server/Core.py +++ b/src/lib/Bcfg2/Server/Core.py @@ -1214,7 +1214,7 @@ class BaseCore(object): for plugin in self.plugins.values(): plugin.set_debug(debug) rv = self.set_core_debug(address, debug) - return self.set_fam_debug(address, debug) and rv + return self.fam.set_debug(debug) and rv @exposed def set_core_debug(self, _, debug): @@ -1232,10 +1232,9 @@ class BaseCore(object): self.logger.info("Core: debug = %s" % debug) levels = self._loglevels[self.debug_flag] for handler in logging.root.handlers: - level = levels.get(handler.get_name(), levels['default']) + level = levels.get(handler.name, levels['default']) self.logger.debug("Setting %s log handler to %s" % - (handler.get_name(), - logging.getLevelName(level))) + (handler.name, logging.getLevelName(level))) handler.setLevel(level) return self.debug_flag diff --git a/src/lib/Bcfg2/Server/Plugin/helpers.py b/src/lib/Bcfg2/Server/Plugin/helpers.py index c2252f956..0b81077a3 100644 --- a/src/lib/Bcfg2/Server/Plugin/helpers.py +++ b/src/lib/Bcfg2/Server/Plugin/helpers.py @@ -543,6 +543,7 @@ class XMLFileBacked(FileBacked): def Index(self): self.xdata = lxml.etree.XML(self.data, base_url=self.name, parser=Bcfg2.Server.XMLParser) + self.extras = [] self._follow_xincludes() if self.extras: try: diff --git a/src/lib/Bcfg2/Server/Plugins/Metadata.py b/src/lib/Bcfg2/Server/Plugins/Metadata.py index a81139b5d..8fb3a0998 100644 --- a/src/lib/Bcfg2/Server/Plugins/Metadata.py +++ b/src/lib/Bcfg2/Server/Plugins/Metadata.py @@ -264,31 +264,63 @@ class ClientMetadata(object): # pylint: disable=R0913 def __init__(self, client, profile, groups, bundles, aliases, addresses, categories, uuid, password, version, query): + #: The client hostname (as a string) self.hostname = client + + #: The client profile (as a string) self.profile = profile + + #: The set of all bundles this client gets self.bundles = bundles + + #: A list of all client aliases self.aliases = aliases + + #: A list of all addresses this client is known by self.addresses = addresses + + #: A list of groups this client is a member of self.groups = groups + + #: A dict of categories of this client's groups. Keys are + #: category names, values are corresponding group names. self.categories = categories + + #: The UUID identifier for this client self.uuid = uuid + + #: The Bcfg2 password for this client self.password = password + + #: Connector plugins known to this client self.connectors = [] + + #: The version of the Bcfg2 client this client is running, as + #: a string self.version = version try: + #: The version of the Bcfg2 client this client is running, + #: as a :class:`Bcfg2.version.Bcfg2VersionInfo` object. self.version_info = Bcfg2VersionInfo(version) except (ValueError, AttributeError): self.version_info = None + + #: A :class:`Bcfg2.Server.Plugins.Metadata.MetadataQuery` + #: object for this client. self.query = query # pylint: enable=R0913 def inGroup(self, group): - """Test to see if client is a member of group.""" + """Test to see if client is a member of group. + + :returns: bool """ return group in self.groups def group_in_category(self, category): - """ return the group in the given category that the client is - a member of, or the empty string """ + """ Return the group in the given category that the client is + a member of, or an empty string. + + :returns: string """ for grp in self.query.all_groups_in_category(category): if grp in self.groups: return grp @@ -296,17 +328,59 @@ class ClientMetadata(object): class MetadataQuery(object): - """ object supplied to client metadata to allow client metadata - objects to query metadata without being able to modify it """ + """ This class provides query methods for the metadata of all + clients known to the Bcfg2 server, without being able to modify + that data. + + Note that ``*by_groups()`` and ``*by_profiles()`` behave + differently; for a client to be included in the return value of a + ``*by_groups()`` method, it must be a member of *all* groups + listed in the argument; for a client to be included in the return + value of a ``*by_profiles()`` method, it must have *any* group + listed as its profile group. """ def __init__(self, by_name, get_clients, by_groups, by_profiles, all_groups, all_groups_in_category): - # resolver is set later + #: Get :class:`Bcfg2.Server.Plugins.Metadata.ClientMetadata` + #: object for the given hostname. + #: + #: :returns: Bcfg2.Server.Plugins.Metadata.ClientMetadata self.by_name = by_name + + #: Get a list of hostnames of clients that are in all given + #: groups. + #: + #: :param groups: The groups to check clients for membership in + #: :type groups: list + #: + #: :returns: list of strings self.names_by_groups = self._warn_string(by_groups) + + #: Get a list of hostnames of clients whose profile matches + #: any given profile group. + #: + #: :param profiles: The profiles to check clients for + #: membership in. + #: :type profiles: list + #: :returns: list of strings self.names_by_profiles = self._warn_string(by_profiles) + + #: Get all known client hostnames. + #: + #: :returns: list of strings self.all_clients = get_clients + + #: Get all known group names. + #: + #: :returns: list of strings self.all_groups = all_groups + + #: Get the names of all groups in the given category. + #: + #: :param category: The category to query for groups that + #: belong to it. + #: :type category: string + #: :returns: list of strings self.all_groups_in_category = all_groups_in_category def _warn_string(self, func): @@ -327,22 +401,41 @@ class MetadataQuery(object): return inner def by_groups(self, groups): - """ get a list of ClientMetadata objects that are in all given - groups """ + """ Get a list of + :class:`Bcfg2.Server.Plugins.Metadata.ClientMetadata` objects + that are in all given groups. + + :param groups: The groups to check clients for membership in. + :type groups: list + :returns: list of Bcfg2.Server.Plugins.Metadata.ClientMetadata + objects + """ # don't need to decorate this with _warn_string because # names_by_groups is decorated return [self.by_name(name) for name in self.names_by_groups(groups)] def by_profiles(self, profiles): - """ get a list of ClientMetadata objects that are in any of - the given profiles """ + """ Get a list of + :class:`Bcfg2.Server.Plugins.Metadata.ClientMetadata` objects + that have any of the given groups as their profile. + + :param profiles: The profiles to check clients for membership + in. + :type profiles: list + :returns: list of Bcfg2.Server.Plugins.Metadata.ClientMetadata + objects + """ # don't need to decorate this with _warn_string because # names_by_profiles is decorated return [self.by_name(name) for name in self.names_by_profiles(profiles)] def all(self): - """ get a list of all ClientMetadata objects """ + """ Get a list of all + :class:`Bcfg2.Server.Plugins.Metadata.ClientMetadata` objects. + + :returns: list of Bcfg2.Server.Plugins.Metadata.ClientMetadata + """ return [self.by_name(name) for name in self.all_clients()] diff --git a/src/lib/Bcfg2/Utils.py b/src/lib/Bcfg2/Utils.py index 7d7d26d5d..33da8bd71 100644 --- a/src/lib/Bcfg2/Utils.py +++ b/src/lib/Bcfg2/Utils.py @@ -197,14 +197,20 @@ class Executor(object): :type timeout: float :returns: :class:`Bcfg2.Utils.ExecutorResult` """ - if isinstance(command, str): + if isinstance(command, basestring): cmdstr = command else: cmdstr = " ".join(command) self.logger.debug("Running: %s" % cmdstr) - proc = subprocess.Popen(command, shell=shell, bufsize=16384, - stdin=subprocess.PIPE, stdout=subprocess.PIPE, - stderr=subprocess.PIPE, close_fds=True) + try: + proc = subprocess.Popen(command, shell=shell, bufsize=16384, + close_fds=True, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + except OSError: + return ExecutorResult('', 'No such command: %s' % cmdstr, + 127) if timeout is None: timeout = self.timeout if timeout is not None: |