summaryrefslogtreecommitdiffstats
path: root/src/lib/Bcfg2/Client/Tools
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/Bcfg2/Client/Tools')
-rw-r--r--src/lib/Bcfg2/Client/Tools/POSIX/Hardlink.py1
-rw-r--r--src/lib/Bcfg2/Client/Tools/POSIX/base.py2
-rw-r--r--src/lib/Bcfg2/Client/Tools/SELinux.py2
-rw-r--r--src/lib/Bcfg2/Client/Tools/YUM.py84
-rw-r--r--src/lib/Bcfg2/Client/Tools/__init__.py108
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)