diff options
Diffstat (limited to 'src/lib/Bcfg2/Client/Tools')
-rw-r--r-- | src/lib/Bcfg2/Client/Tools/POSIX/Hardlink.py | 1 | ||||
-rw-r--r-- | src/lib/Bcfg2/Client/Tools/POSIX/base.py | 2 | ||||
-rw-r--r-- | src/lib/Bcfg2/Client/Tools/SELinux.py | 2 | ||||
-rw-r--r-- | src/lib/Bcfg2/Client/Tools/YUM.py | 84 | ||||
-rw-r--r-- | src/lib/Bcfg2/Client/Tools/__init__.py | 108 |
5 files changed, 140 insertions, 57 deletions
diff --git a/src/lib/Bcfg2/Client/Tools/POSIX/Hardlink.py b/src/lib/Bcfg2/Client/Tools/POSIX/Hardlink.py index 896ca5f49..64a0b1e15 100644 --- a/src/lib/Bcfg2/Client/Tools/POSIX/Hardlink.py +++ b/src/lib/Bcfg2/Client/Tools/POSIX/Hardlink.py @@ -12,5 +12,4 @@ class POSIXHardlink(POSIXLinkTool): return os.path.samefile(entry.get('name'), entry.get('to')) def _link(self, entry): - ## TODO: set permissions return os.link(entry.get('to'), entry.get('name')) diff --git a/src/lib/Bcfg2/Client/Tools/POSIX/base.py b/src/lib/Bcfg2/Client/Tools/POSIX/base.py index b867fa3d8..f46875743 100644 --- a/src/lib/Bcfg2/Client/Tools/POSIX/base.py +++ b/src/lib/Bcfg2/Client/Tools/POSIX/base.py @@ -687,7 +687,7 @@ class POSIXTool(Bcfg2.Client.Tools.Tool): if path is None: path = entry.get("name") cur = path - while cur != '/': + while cur and cur != '/': if not os.path.exists(cur): created.append(cur) cur = os.path.dirname(cur) diff --git a/src/lib/Bcfg2/Client/Tools/SELinux.py b/src/lib/Bcfg2/Client/Tools/SELinux.py index 08d943251..451495be2 100644 --- a/src/lib/Bcfg2/Client/Tools/SELinux.py +++ b/src/lib/Bcfg2/Client/Tools/SELinux.py @@ -360,7 +360,7 @@ class SELinuxEntryHandler(object): """ find extra entries of this entry type """ specified = [self._key(e) for e in self.tool.getSupportedEntries() - if e.get("type") == self.etype] + if e.tag == "SE%s" % self.etype.title()] try: records = self.custom_records except ValueError: diff --git a/src/lib/Bcfg2/Client/Tools/YUM.py b/src/lib/Bcfg2/Client/Tools/YUM.py index 1fe275c2c..c9fae7fc7 100644 --- a/src/lib/Bcfg2/Client/Tools/YUM.py +++ b/src/lib/Bcfg2/Client/Tools/YUM.py @@ -123,7 +123,7 @@ class YUM(Bcfg2.Client.Tools.PkgTool): ('Package', 'rpm'), ('Path', 'ignore')] - __req__ = {'Package': ['name'], + __req__ = {'Package': ['type'], 'Path': ['type']} conflicts = ['YUM24', 'RPM', 'RPMng', 'YUMng'] @@ -287,6 +287,17 @@ class YUM(Bcfg2.Client.Tools.PkgTool): return self.yumbase.rpmdb.returnGPGPubkeyPackages() return self.yumbase.rpmdb.searchNevra(name='gpg-pubkey') + def missing_attrs(self, entry): + """ Implementing from superclass to check for existence of either + name or group attribute for Package entry in the case of a YUM + group. """ + missing = Bcfg2.Client.Tools.PkgTool.missing_attrs(self, entry) + + if entry.get('name', None) == None and \ + entry.get('group', None) == None: + missing += ['name', 'group'] + return missing + def _verifyHelper(self, pkg_obj): """ _verifyHelper primarly deals with a yum bug where the pkg_obj.verify() method does not properly take into count multilib @@ -409,8 +420,12 @@ class YUM(Bcfg2.Client.Tools.PkgTool): if entry.get('version', False) == 'auto': self._fixAutoVersion(entry) - self.logger.debug("Verifying package instances for %s" % - entry.get('name')) + if entry.get('group'): + self.logger.debug("Verifying packages for group %s" % + entry.get('group')) + else: + self.logger.debug("Verifying package instances for %s" % + entry.get('name')) self.verify_cache = dict() # Used for checking multilib packages self.modlists[entry] = modlist @@ -423,14 +438,58 @@ class YUM(Bcfg2.Client.Tools.PkgTool): entry.get('pkg_checks', 'true').lower() == 'true' pkg_verify = self.pkg_verify and \ entry.get('pkg_verify', 'true').lower() == 'true' + yum_group = False if entry.get('name') == 'gpg-pubkey': all_pkg_objs = self._getGPGKeysAsPackages() pkg_verify = False # No files here to verify + elif entry.get('group'): + entry.set('name', 'group:%s' % entry.get('group')) + yum_group = True + all_pkg_objs = [] + instances = [] + if self.yumbase.comps.has_group(entry.get('group')): + group = self.yumbase.comps.return_group(entry.get('group')) + group_packages = [p + for p, d in group.mandatory_packages.items() + if d] + group_type = entry.get('choose', 'default') + if group_type in ['default', 'optional', 'all']: + group_packages += [p + for p, d in + group.default_packages.items() + if d] + if group_type in ['optional', 'all']: + group_packages += [p + for p, d in + group.optional_packages.items() + if d] + if len(group_packages) == 0: + self.logger.error("No packages found for group %s" % + entry.get("group")) + for pkg in group_packages: + # create package instances for each package in yum group + instance = Bcfg2.Client.XML.SubElement(entry, 'Package') + instance.attrib['name'] = pkg + instance.attrib['type'] = 'yum' + try: + newest = \ + self.yumbase.pkgSack.returnNewestByName(pkg)[0] + instance.attrib['version'] = newest['version'] + instance.attrib['epoch'] = newest['epoch'] + instance.attrib['release'] = newest['release'] + except: # pylint: disable=W0702 + self.logger.info("Error finding newest package " + "for %s" % + pkg) + instance.attrib['version'] = 'any' + instances.append(instance) + else: + self.logger.error("Group not found: %s" % entry.get("group")) else: all_pkg_objs = \ self.yumbase.rpmdb.searchNevra(name=entry.get('name')) - if len(all_pkg_objs) == 0: + if len(all_pkg_objs) == 0 and yum_group != True: # Some sort of virtual capability? Try to resolve it all_pkg_objs = self.yumbase.rpmdb.searchProvides(entry.get('name')) if len(all_pkg_objs) > 0: @@ -441,7 +500,13 @@ class YUM(Bcfg2.Client.Tools.PkgTool): self.logger.info(" %s" % pkg) for inst in instances: - nevra = build_yname(entry.get('name'), inst) + if yum_group: + # the entry is not the name of the package + nevra = build_yname(inst.get('name'), inst) + all_pkg_objs = \ + self.yumbase.rpmdb.searchNevra(name=inst.get('name')) + else: + nevra = build_yname(entry.get('name'), inst) if nevra in pkg_cache: continue # Ignore duplicate instances else: @@ -455,7 +520,10 @@ class YUM(Bcfg2.Client.Tools.PkgTool): stat['version_fail'] = False stat['verify'] = {} stat['verify_fail'] = False - stat['pkg'] = entry + if yum_group: + stat['pkg'] = inst + else: + stat['pkg'] = entry stat['modlist'] = modlist if inst.get('verify_flags'): # this splits on either space or comma @@ -624,7 +692,9 @@ class YUM(Bcfg2.Client.Tools.PkgTool): else: install_only = False - if virt_pkg or (install_only and not self.setup['kevlar']): + if virt_pkg or \ + (install_only and not self.setup['kevlar']) or \ + yum_group: # virtual capability supplied, we are probably dealing # with multiple packages of different names. This check # doesn't make a lot of since in this case. diff --git a/src/lib/Bcfg2/Client/Tools/__init__.py b/src/lib/Bcfg2/Client/Tools/__init__.py index cd86a2a4b..a4a68ea3b 100644 --- a/src/lib/Bcfg2/Client/Tools/__init__.py +++ b/src/lib/Bcfg2/Client/Tools/__init__.py @@ -3,10 +3,10 @@ import os import sys import stat -import select +import Bcfg2.Client import Bcfg2.Client.XML from Bcfg2.Utils import Executor, ClassName -from Bcfg2.Compat import input, walk_packages # pylint: disable=W0622 +from Bcfg2.Compat import walk_packages # pylint: disable=W0622 __all__ = [m[1] for m in walk_packages(path=__path__)] @@ -113,25 +113,34 @@ class Tool(object): #: A list of all entries handled by this tool self.handled = [] - for struct in config: + self._analyze_config() + self._check_execs() + + def _analyze_config(self): + """ Analyze the config at tool initialization-time for + important and handled entries """ + for struct in self.config: for entry in struct: if (entry.tag == 'Path' and entry.get('important', 'false').lower() == 'true'): self.__important__.append(entry.get('name')) - if self.handlesEntry(entry): - self.handled.append(entry) + self.handled = self.getSupportedEntries() + + def _check_execs(self): + """ Check all executables used by this tool to ensure that + they exist and are executable """ for filename in self.__execs__: try: mode = stat.S_IMODE(os.stat(filename)[stat.ST_MODE]) - if mode & stat.S_IEXEC != stat.S_IEXEC: - raise ToolInstantiationError("%s: %s not executable" % - (self.name, filename)) except OSError: raise ToolInstantiationError(sys.exc_info()[1]) except: raise ToolInstantiationError("%s: Failed to stat %s" % - (self.name, filename), - exc_info=1) + (self.name, filename)) + if not mode & stat.S_IEXEC: + raise ToolInstantiationError("%s: %s not executable" % + (self.name, filename)) + def BundleUpdated(self, bundle, states): # pylint: disable=W0613 """ Callback that is invoked when a bundle has been updated. @@ -185,11 +194,13 @@ class Tool(object): if self.canVerify(entry): try: func = getattr(self, "Verify%s" % entry.tag) - states[entry] = func(entry, mods) except AttributeError: self.logger.error("%s: Cannot verify %s entries" % (self.name, entry.tag)) - except: + continue + try: + states[entry] = func(entry, mods) + except: # pylint: disable=W0702 self.logger.error("%s: Unexpected failure verifying %s" % (self.name, self.primarykey(entry)), @@ -213,14 +224,16 @@ class Tool(object): :returns: None """ for entry in entries: try: - func = getattr(self, "Install%s" % (entry.tag)) - states[entry] = func(entry) - if states[entry]: - self.modified.append(entry) + func = getattr(self, "Install%s" % entry.tag) except AttributeError: self.logger.error("%s: Cannot install %s entries" % (self.name, entry.tag)) - except: + continue + try: + states[entry] = func(entry) + if states[entry]: + self.modified.append(entry) + except: # pylint: disable=W0702 self.logger.error("%s: Unexpected failure installing %s" % (self.name, self.primarykey(entry)), exc_info=1) @@ -409,6 +422,19 @@ class PkgTool(Tool): """ raise NotImplementedError + def _get_package_command(self, packages): + """ Get the command to install the given list of packages. + + :param packages: The Package entries to install + :type packages: list of lxml.etree._Element + :returns: string - the command to run + """ + pkgargs = " ".join(self.pkgtool[1][0] % + tuple(pkg.get(field) + for field in self.pkgtool[1][1]) + for pkg in packages) + return self.pkgtool[0] % pkgargs + def Install(self, packages, states): """ Run a one-pass install where all required packages are installed with a single command, followed by single package @@ -422,12 +448,9 @@ class PkgTool(Tool): self.logger.info("Trying single pass package install for pkgtype %s" % self.pkgtype) - data = [tuple([pkg.get(field) for field in self.pkgtool[1][1]]) - for pkg in packages] - pkgargs = " ".join([self.pkgtool[1][0] % datum for datum in data]) - - self.logger.debug("Installing packages: %s" % pkgargs) - if self.cmd.run(self.pkgtool[0] % pkgargs): + pkgcmd = self._get_package_command(packages) + self.logger.debug("Running command: %s" % pkgcmd) + if self.cmd.run(pkgcmd): self.logger.info("Single Pass Succeded") # set all package states to true and flush workqueues pkgnames = [pkg.get('name') for pkg in packages] @@ -436,7 +459,7 @@ class PkgTool(Tool): and entry.get('type') == self.pkgtype and entry.get('name') in pkgnames): self.logger.debug('Setting state to true for pkg %s' % - (entry.get('name'))) + entry.get('name')) states[entry] = True self.RefreshPackages() else: @@ -452,18 +475,13 @@ class PkgTool(Tool): else: self.logger.info("Installing pkg %s version %s" % (pkg.get('name'), pkg.get('version'))) - if self.cmd.run( - self.pkgtool[0] % - (self.pkgtool[1][0] % - tuple([pkg.get(field) - for field in self.pkgtool[1][1]]))): + if self.cmd.run(self._get_package_command([pkg])): states[pkg] = True else: self.logger.error("Failed to install package %s" % - (pkg.get('name'))) + pkg.get('name')) self.RefreshPackages() - for entry in [ent for ent in packages if states[ent]]: - self.modified.append(entry) + self.modified.extend(entry for entry in packages if states[entry]) def RefreshPackages(self): """ Refresh the internal representation of the package @@ -557,11 +575,13 @@ class SvcTool(Tool): if self.setup['servicemode'] == 'disabled': return - for entry in [ent for ent in bundle if self.handlesEntry(ent)]: - restart = entry.get("restart", "true") - if (restart.lower() == "false" or - (restart.lower() == "interactive" and - not self.setup['interactive'])): + for entry in bundle: + if not self.handlesEntry(entry): + continue + + restart = entry.get("restart", "true").lower() + if (restart == "false" or + (restart == "interactive" and not self.setup['interactive'])): continue success = False @@ -570,14 +590,8 @@ class SvcTool(Tool): success = self.stop_service(entry) elif entry.get('name') not in self.restarted: if self.setup['interactive']: - prompt = ('Restart service %s?: (y/N): ' % - entry.get('name')) - # flush input buffer - while len(select.select([sys.stdin.fileno()], [], [], - 0.0)[0]) > 0: - os.read(sys.stdin.fileno(), 4096) - ans = input(prompt) - if ans not in ['y', 'Y']: + if not Bcfg2.Client.prompt('Restart service %s? (y/N) ' + % entry.get('name')): continue success = self.restart_service(entry) if success: @@ -593,8 +607,8 @@ class SvcTool(Tool): install_entries = [] for entry in entries: if entry.get('install', 'true').lower() == 'false': - self.logger.info("Service %s installation is false. Skipping " - "installation." % (entry.get('name'))) + self.logger.info("Installation is false for %s:%s, skipping" % + (entry.tag, entry.get('name'))) else: install_entries.append(entry) return Tool.Install(self, install_entries, states) |