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/APK.py2
-rw-r--r--src/lib/Bcfg2/Client/Tools/Action.py20
-rw-r--r--src/lib/Bcfg2/Client/Tools/Chkconfig.py97
-rw-r--r--src/lib/Bcfg2/Client/Tools/DebInit.py105
-rw-r--r--src/lib/Bcfg2/Client/Tools/Encap.py2
-rw-r--r--src/lib/Bcfg2/Client/Tools/FreeBSDPackage.py4
-rw-r--r--src/lib/Bcfg2/Client/Tools/IPS.py6
-rw-r--r--src/lib/Bcfg2/Client/Tools/MacPorts.py2
-rw-r--r--src/lib/Bcfg2/Client/Tools/POSIX/Device.py4
-rw-r--r--src/lib/Bcfg2/Client/Tools/POSIX/Directory.py6
-rw-r--r--src/lib/Bcfg2/Client/Tools/POSIX/File.py16
-rw-r--r--src/lib/Bcfg2/Client/Tools/POSIX/base.py20
-rw-r--r--src/lib/Bcfg2/Client/Tools/POSIXUsers.py6
-rw-r--r--src/lib/Bcfg2/Client/Tools/Pacman.py6
-rw-r--r--src/lib/Bcfg2/Client/Tools/Portage.py14
-rw-r--r--src/lib/Bcfg2/Client/Tools/RcUpdate.py118
-rw-r--r--src/lib/Bcfg2/Client/Tools/SELinux.py52
-rw-r--r--src/lib/Bcfg2/Client/Tools/SMF.py23
-rw-r--r--src/lib/Bcfg2/Client/Tools/SYSV.py4
-rw-r--r--src/lib/Bcfg2/Client/Tools/Systemd.py2
-rw-r--r--src/lib/Bcfg2/Client/Tools/Upstart.py4
-rw-r--r--src/lib/Bcfg2/Client/Tools/VCS.py112
-rw-r--r--src/lib/Bcfg2/Client/Tools/YUM.py93
-rw-r--r--src/lib/Bcfg2/Client/Tools/__init__.py16
24 files changed, 486 insertions, 248 deletions
diff --git a/src/lib/Bcfg2/Client/Tools/APK.py b/src/lib/Bcfg2/Client/Tools/APK.py
index 8a02b7d6d..58641ed37 100644
--- a/src/lib/Bcfg2/Client/Tools/APK.py
+++ b/src/lib/Bcfg2/Client/Tools/APK.py
@@ -32,7 +32,7 @@ class APK(Bcfg2.Client.Tools.PkgTool):
"""Verify Package status for entry."""
if not 'version' in entry.attrib:
self.logger.info("Cannot verify unversioned package %s" %
- (entry.attrib['name']))
+ entry.attrib['name'])
return False
if entry.attrib['name'] in self.installed:
diff --git a/src/lib/Bcfg2/Client/Tools/Action.py b/src/lib/Bcfg2/Client/Tools/Action.py
index 87565d96d..0166e4c00 100644
--- a/src/lib/Bcfg2/Client/Tools/Action.py
+++ b/src/lib/Bcfg2/Client/Tools/Action.py
@@ -20,22 +20,29 @@ class Action(Bcfg2.Client.Tools.Tool):
the whitelist or blacklist """
if self.setup['decision'] == 'whitelist' and \
not matches_white_list(action, self.setup['decision_list']):
- self.logger.info("In whitelist mode: suppressing Action:" + \
+ self.logger.info("In whitelist mode: suppressing Action: %s" %
action.get('name'))
return False
if self.setup['decision'] == 'blacklist' and \
not passes_black_list(action, self.setup['decision_list']):
- self.logger.info("In blacklist mode: suppressing Action:" + \
+ self.logger.info("In blacklist mode: suppressing Action: %s" %
action.get('name'))
return False
return True
def RunAction(self, entry):
"""This method handles command execution and status return."""
+ shell = False
+ shell_string = ''
+ if entry.get('shell', 'false') == 'true':
+ shell = True
+ shell_string = '(in shell) '
+
if not self.setup['dryrun']:
if self.setup['interactive']:
- prompt = ('Run Action %s, %s: (y/N): ' %
- (entry.get('name'), entry.get('command')))
+ prompt = ('Run Action %s%s, %s: (y/N): ' %
+ (shell_string, entry.get('name'),
+ entry.get('command')))
# flush input buffer
while len(select.select([sys.stdin.fileno()], [], [],
0.0)[0]) > 0:
@@ -48,8 +55,9 @@ class Action(Bcfg2.Client.Tools.Tool):
self.logger.debug("Action: Deferring execution of %s due "
"to build mode" % entry.get('command'))
return False
- self.logger.debug("Running Action %s" % (entry.get('name')))
- rv = self.cmd.run(entry.get('command'))
+ self.logger.debug("Running Action %s %s" %
+ (shell_string, entry.get('name')))
+ rv = self.cmd.run(entry.get('command'), shell=shell)
self.logger.debug("Action: %s got return code %s" %
(entry.get('command'), rv.retval))
entry.set('rc', str(rv.retval))
diff --git a/src/lib/Bcfg2/Client/Tools/Chkconfig.py b/src/lib/Bcfg2/Client/Tools/Chkconfig.py
index ec7f462b3..156f76159 100644
--- a/src/lib/Bcfg2/Client/Tools/Chkconfig.py
+++ b/src/lib/Bcfg2/Client/Tools/Chkconfig.py
@@ -19,25 +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."""
- 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:
@@ -46,37 +43,75 @@ 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') == 'ignore':
+ # 'ignore' should verify
+ current_svcstatus = True
+ svcstatus = True
+ else:
+ svcstatus = self.check_service(entry)
if entry.get('status') == 'on':
- entry.set('current_status', 'off')
- else:
- entry.set('current_status', 'on')
- return status
+ 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."""
- 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':
- rv &= self.cmd.run((rcmd + " --level 0123456") %
- (entry.get('name'),
- entry.get('status'))).success
- if entry.get("current_status") == "on":
- 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":
- 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 ca556e98b..761c51db7 100644
--- a/src/lib/Bcfg2/Client/Tools/DebInit.py
+++ b/src/lib/Bcfg2/Client/Tools/DebInit.py
@@ -16,15 +16,13 @@ class DebInit(Bcfg2.Client.Tools.SvcTool):
__handles__ = [('Service', 'deb')]
__req__ = {'Service': ['name', 'status']}
svcre = \
- re.compile("/etc/.*/(?P<action>[SK])(?P<sequence>\d+)(?P<name>\S+)")
+ re.compile(r'/etc/.*/(?P<action>[SK])(?P<sequence>\d+)(?P<name>\S+)')
- # implement entry (Verify|Install) ops
- def VerifyService(self, entry, _):
- """Verify Service status for entry."""
-
- if entry.get('status') == 'ignore':
- return True
+ 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 = []
@@ -54,9 +52,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 +70,47 @@ 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)
+
+ 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 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 +118,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."""
@@ -116,6 +170,3 @@ class DebInit(Bcfg2.Client.Tools.SvcTool):
# Extra service removal is nonsensical
# Extra services need to be reflected in the config
return
-
- def get_svc_command(self, service, action):
- return '/usr/sbin/invoke-rc.d %s %s' % (service.get('name'), action)
diff --git a/src/lib/Bcfg2/Client/Tools/Encap.py b/src/lib/Bcfg2/Client/Tools/Encap.py
index 678e0f00c..270f0a5f2 100644
--- a/src/lib/Bcfg2/Client/Tools/Encap.py
+++ b/src/lib/Bcfg2/Client/Tools/Encap.py
@@ -13,7 +13,7 @@ class Encap(Bcfg2.Client.Tools.PkgTool):
__req__ = {'Package': ['version', 'url']}
pkgtype = 'encap'
pkgtool = ("/usr/local/bin/epkg -l -f -q %s", ("%s", ["url"]))
- splitter = re.compile('.*/(?P<name>[\w-]+)\-(?P<version>[\w\.+-]+)')
+ splitter = re.compile(r'.*/(?P<name>[\w-]+)\-(?P<version>[\w\.+-]+)')
def RefreshPackages(self):
"""Try to find encap packages."""
diff --git a/src/lib/Bcfg2/Client/Tools/FreeBSDPackage.py b/src/lib/Bcfg2/Client/Tools/FreeBSDPackage.py
index 635318805..31925fa3c 100644
--- a/src/lib/Bcfg2/Client/Tools/FreeBSDPackage.py
+++ b/src/lib/Bcfg2/Client/Tools/FreeBSDPackage.py
@@ -21,7 +21,7 @@ class FreeBSDPackage(Bcfg2.Client.Tools.PkgTool):
def RefreshPackages(self):
self.installed = {}
packages = self.cmd.run("/usr/sbin/pkg_info -a -E").stdout.splitlines()
- pattern = re.compile('(.*)-(\d.*)')
+ pattern = re.compile(r'(.*)-(\d.*)')
for pkg in packages:
if pattern.match(pkg):
name = pattern.match(pkg).group(1)
@@ -31,7 +31,7 @@ class FreeBSDPackage(Bcfg2.Client.Tools.PkgTool):
def VerifyPackage(self, entry, _):
if not 'version' in entry.attrib:
self.logger.info("Cannot verify unversioned package %s" %
- (entry.attrib['name']))
+ entry.attrib['name'])
return False
if entry.attrib['name'] in self.installed:
if self.installed[entry.attrib['name']] == entry.attrib['version']:
diff --git a/src/lib/Bcfg2/Client/Tools/IPS.py b/src/lib/Bcfg2/Client/Tools/IPS.py
index dc4d48235..aff276c3a 100644
--- a/src/lib/Bcfg2/Client/Tools/IPS.py
+++ b/src/lib/Bcfg2/Client/Tools/IPS.py
@@ -51,9 +51,9 @@ class IPS(Bcfg2.Client.Tools.PkgTool):
pass
else:
if entry.get('version') != self.installed[pname]:
- self.logger.debug("IPS: Package %s: have %s want %s" \
- % (pname, self.installed[pname],
- entry.get('version')))
+ self.logger.debug("IPS: Package %s: have %s want %s" %
+ (pname, self.installed[pname],
+ entry.get('version')))
return False
# need to implement pkg chksum validation
diff --git a/src/lib/Bcfg2/Client/Tools/MacPorts.py b/src/lib/Bcfg2/Client/Tools/MacPorts.py
index bc3765ec6..bd9d24df3 100644
--- a/src/lib/Bcfg2/Client/Tools/MacPorts.py
+++ b/src/lib/Bcfg2/Client/Tools/MacPorts.py
@@ -38,7 +38,7 @@ class MacPorts(Bcfg2.Client.Tools.PkgTool):
"""Verify Package status for entry."""
if not 'version' in entry.attrib:
self.logger.info("Cannot verify unversioned package %s" %
- (entry.attrib['name']))
+ entry.attrib['name'])
return False
if entry.attrib['name'] in self.installed:
diff --git a/src/lib/Bcfg2/Client/Tools/POSIX/Device.py b/src/lib/Bcfg2/Client/Tools/POSIX/Device.py
index d5aaf069d..9b84adad0 100644
--- a/src/lib/Bcfg2/Client/Tools/POSIX/Device.py
+++ b/src/lib/Bcfg2/Client/Tools/POSIX/Device.py
@@ -12,8 +12,8 @@ class POSIXDevice(POSIXTool):
def fully_specified(self, entry):
if entry.get('dev_type') in ['block', 'char']:
# check if major/minor are properly specified
- if (entry.get('major') == None or
- entry.get('minor') == None):
+ if (entry.get('major') is None or
+ entry.get('minor') is None):
return False
return True
diff --git a/src/lib/Bcfg2/Client/Tools/POSIX/Directory.py b/src/lib/Bcfg2/Client/Tools/POSIX/Directory.py
index 9d0fe05e0..675a4461a 100644
--- a/src/lib/Bcfg2/Client/Tools/POSIX/Directory.py
+++ b/src/lib/Bcfg2/Client/Tools/POSIX/Directory.py
@@ -36,14 +36,14 @@ 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
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]):
@@ -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)
diff --git a/src/lib/Bcfg2/Client/Tools/POSIX/File.py b/src/lib/Bcfg2/Client/Tools/POSIX/File.py
index 9b95d2234..9f47fb53a 100644
--- a/src/lib/Bcfg2/Client/Tools/POSIX/File.py
+++ b/src/lib/Bcfg2/Client/Tools/POSIX/File.py
@@ -34,13 +34,11 @@ class POSIXFile(POSIXTool):
def _get_data(self, entry):
""" Get a tuple of (<file data>, <is binary>) for the given entry """
- is_binary = False
- if entry.get('encoding', 'ascii') == 'base64':
- tempdata = b64decode(entry.text)
- is_binary = True
-
- elif entry.get('empty', 'false') == 'true':
+ is_binary = entry.get('encoding', 'ascii') == 'base64'
+ if entry.get('empty', 'false') == 'true' or not entry.text:
tempdata = ''
+ elif is_binary:
+ tempdata = b64decode(entry.text)
else:
tempdata = entry.text
if isinstance(tempdata, unicode) and unicode != str:
@@ -148,8 +146,8 @@ class POSIXFile(POSIXTool):
return POSIXTool.install(self, entry) and rv
- def _get_diffs(self, entry, interactive=False, sensitive=False,
- is_binary=False, content=None):
+ def _get_diffs(self, entry, interactive=False, # pylint: disable=R0912
+ sensitive=False, is_binary=False, content=None):
""" generate the necessary diffs for entry """
if not interactive and sensitive:
return
@@ -165,6 +163,8 @@ class POSIXFile(POSIXTool):
# prompts for -I and the reports
try:
content = open(entry.get('name')).read()
+ except UnicodeDecodeError:
+ content = open(entry.get('name'), encoding='utf-8').read()
except IOError:
self.logger.error("POSIX: Failed to read %s: %s" %
(entry.get("name"), sys.exc_info()[1]))
diff --git a/src/lib/Bcfg2/Client/Tools/POSIX/base.py b/src/lib/Bcfg2/Client/Tools/POSIX/base.py
index f46875743..16fe0acb5 100644
--- a/src/lib/Bcfg2/Client/Tools/POSIX/base.py
+++ b/src/lib/Bcfg2/Client/Tools/POSIX/base.py
@@ -275,7 +275,7 @@ class POSIXTool(Bcfg2.Client.Tools.Tool):
if path is None:
path = entry.get("name")
context = entry.get("secontext")
- if context is None:
+ if not context:
# no context listed
return True
@@ -520,13 +520,19 @@ class POSIXTool(Bcfg2.Client.Tools.Tool):
"Current mtime is %s but should be %s" %
(path, mtime, entry.get('mtime')))
- if HAS_SELINUX and entry.get("secontext"):
+ if HAS_SELINUX:
+ wanted_secontext = None
if entry.get("secontext") == "__default__":
- wanted_secontext = \
- selinux.matchpathcon(path, 0)[1].split(":")[2]
+ try:
+ wanted_secontext = \
+ selinux.matchpathcon(path, 0)[1].split(":")[2]
+ except OSError:
+ errors.append("%s has no default SELinux context" %
+ entry.get("name"))
else:
wanted_secontext = entry.get("secontext")
- if attrib['current_secontext'] != wanted_secontext:
+ if (wanted_secontext and
+ attrib['current_secontext'] != wanted_secontext):
errors.append("SELinux context for path %s is incorrect. "
"Current context is %s but should be %s" %
(path, attrib['current_secontext'],
@@ -712,8 +718,8 @@ class POSIXTool(Bcfg2.Client.Tools.Tool):
tmpentry.set('mode', oct_mode(newmode))
for acl in tmpentry.findall('ACL'):
acl.set('perms',
- oct_mode(self._norm_acl_perms(acl.get('perms')) | \
- ACL_MAP['x']))
+ oct_mode(self._norm_acl_perms(acl.get('perms')) |
+ ACL_MAP['x']))
for cpath in created:
rv &= self._set_perms(tmpentry, path=cpath)
return rv
diff --git a/src/lib/Bcfg2/Client/Tools/POSIXUsers.py b/src/lib/Bcfg2/Client/Tools/POSIXUsers.py
index 99ed3c7d9..8226392f9 100644
--- a/src/lib/Bcfg2/Client/Tools/POSIXUsers.py
+++ b/src/lib/Bcfg2/Client/Tools/POSIXUsers.py
@@ -154,7 +154,8 @@ class POSIXUsers(Bcfg2.Client.Tools.Tool):
if entry.get("current_exists", "true") == "true":
# verify supplemental groups
actual = [g[0] for g in self.user_supplementary_groups(entry)]
- expected = [e.text for e in entry.findall("MemberOf")]
+ expected = [e.get("group", e.text).strip()
+ for e in entry.findall("MemberOf")]
if set(expected) != set(actual):
entry.set('qtext',
"\n".join([entry.get('qtext', '')] +
@@ -252,7 +253,8 @@ class POSIXUsers(Bcfg2.Client.Tools.Tool):
if entry.get('uid'):
cmd.extend(['-u', entry.get('uid')])
cmd.extend(['-g', entry.get('group')])
- extras = [e.text for e in entry.findall("MemberOf")]
+ extras = [e.get("group", e.text).strip()
+ for e in entry.findall("MemberOf")]
if extras:
cmd.extend(['-G', ",".join(extras)])
cmd.extend(['-d', entry.get('home')])
diff --git a/src/lib/Bcfg2/Client/Tools/Pacman.py b/src/lib/Bcfg2/Client/Tools/Pacman.py
index 12785afee..a4cfd3315 100644
--- a/src/lib/Bcfg2/Client/Tools/Pacman.py
+++ b/src/lib/Bcfg2/Client/Tools/Pacman.py
@@ -30,12 +30,12 @@ class Pacman(Bcfg2.Client.Tools.PkgTool):
def VerifyPackage(self, entry, _):
'''Verify Package status for entry'''
- self.logger.info("VerifyPackage : %s : %s" % entry.get('name'),
- entry.get('version'))
+ self.logger.info("VerifyPackage: %s : %s" % (entry.get('name'),
+ entry.get('version')))
if not 'version' in entry.attrib:
self.logger.info("Cannot verify unversioned package %s" %
- (entry.attrib['name']))
+ entry.attrib['name'])
return False
if entry.attrib['name'] in self.installed:
diff --git a/src/lib/Bcfg2/Client/Tools/Portage.py b/src/lib/Bcfg2/Client/Tools/Portage.py
index 6b38d7dec..2d8b66ce5 100644
--- a/src/lib/Bcfg2/Client/Tools/Portage.py
+++ b/src/lib/Bcfg2/Client/Tools/Portage.py
@@ -13,8 +13,8 @@ class Portage(Bcfg2.Client.Tools.PkgTool):
__req__ = {'Package': ['name', 'version']}
pkgtype = 'ebuild'
# requires a working PORTAGE_BINHOST in make.conf
- _binpkgtool = ('emerge --getbinpkgonly %s', ('=%s-%s', \
- ['name', 'version']))
+ _binpkgtool = ('emerge --getbinpkgonly %s', ('=%s-%s', ['name',
+ 'version']))
pkgtool = ('emerge %s', ('=%s-%s', ['name', 'version']))
def __init__(self, logger, cfg, setup):
@@ -22,7 +22,7 @@ class Portage(Bcfg2.Client.Tools.PkgTool):
Bcfg2.Client.Tools.PkgTool.__init__(self, logger, cfg, setup)
self._initialised = True
self.__important__ = self.__important__ + ['/etc/make.conf']
- self._pkg_pattern = re.compile('(.*)-(\d.*)')
+ self._pkg_pattern = re.compile(r'(.*)-(\d.*)')
self._ebuild_pattern = re.compile('(ebuild|binary)')
self.cfg = cfg
self.installed = {}
@@ -74,10 +74,10 @@ class Portage(Bcfg2.Client.Tools.PkgTool):
self.logger.debug('Running equery check on %s' %
entry.get('name'))
- for line in self.cmd.run(["/usr/bin/equery", "-N", "check",
- '=%s-%s' %
- (entry.get('name'),
- version)]).stdout.splitlines():
+ for line in self.cmd.run(
+ ["/usr/bin/equery", "-N", "check",
+ '=%s-%s' % (entry.get('name'),
+ entry.get('version'))]).stdout.splitlines():
if '!!!' in line and line.split()[1] not in modlist:
return False
diff --git a/src/lib/Bcfg2/Client/Tools/RcUpdate.py b/src/lib/Bcfg2/Client/Tools/RcUpdate.py
index 552b27842..8e9626521 100644
--- a/src/lib/Bcfg2/Client/Tools/RcUpdate.py
+++ b/src/lib/Bcfg2/Client/Tools/RcUpdate.py
@@ -12,18 +12,47 @@ class RcUpdate(Bcfg2.Client.Tools.SvcTool):
__handles__ = [('Service', 'rc-update')]
__req__ = {'Service': ['name', 'status']}
+ def get_enabled_svcs(self):
+ """
+ Return a list of all enabled services.
+ """
+ return [line.split()[0]
+ for line in self.cmd.run(['/bin/rc-status',
+ '-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
-
- # check if service is enabled
- result = self.cmd.run(["/sbin/rc-update", "show", "default"])
- is_enabled = entry.get("name") in result.stdout
+ current_bootstatus = self.verify_bootstatus(entry, bootstatus)
# check if init script exists
try:
@@ -33,47 +62,62 @@ class RcUpdate(Bcfg2.Client.Tools.SvcTool):
entry.get('name'))
return False
- # check if service is enabled
- 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')
- return False
+ 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
- elif entry.get('status') == 'off' and (is_enabled or is_running):
+ if svcstatus:
entry.set('current_status', 'on')
- return False
+ else:
+ entry.set('current_status', 'off')
- return True
+ return current_bootstatus and current_svcstatus
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."""
- allsrv = [line.split()[0]
- for line in self.cmd.run(['/bin/rc-status',
- '-s']).stdout.splitlines()
- if 'started' in line]
+ allsrv = self.get_enabled_svcs()
self.logger.debug('Found active services:')
self.logger.debug(allsrv)
specified = [srv.get('name') for srv in self.getSupportedEntries()]
diff --git a/src/lib/Bcfg2/Client/Tools/SELinux.py b/src/lib/Bcfg2/Client/Tools/SELinux.py
index 451495be2..0b4aba60d 100644
--- a/src/lib/Bcfg2/Client/Tools/SELinux.py
+++ b/src/lib/Bcfg2/Client/Tools/SELinux.py
@@ -12,6 +12,7 @@ import seobject
import Bcfg2.Client.XML
import Bcfg2.Client.Tools
from Bcfg2.Client.Tools.POSIX.File import POSIXFile
+from Bcfg2.Compat import long # pylint: disable=W0622
def pack128(int_val):
@@ -47,7 +48,7 @@ def netmask_itoa(netmask, proto="ipv4"):
if netmask > size:
raise ValueError("Netmask too large: %s" % netmask)
- res = 0L
+ res = long(0)
for i in range(netmask):
res |= 1 << (size - i - 1)
netmask = socket.inet_ntop(family, pack128(res))
@@ -170,7 +171,7 @@ class SELinuxEntryHandler(object):
key_format = ("name",)
value_format = ()
str_format = '%(name)s'
- custom_re = re.compile(' (?P<name>\S+)$')
+ custom_re = re.compile(r' (?P<name>\S+)$')
custom_format = None
def __init__(self, tool, logger, setup, config):
@@ -203,7 +204,16 @@ class SELinuxEntryHandler(object):
type, if the records object supports the customized() method
"""
if hasattr(self.records, "customized") and self.custom_re:
- return dict([(k, self.all_records[k]) for k in self.custom_keys])
+ rv = dict()
+ for key in self.custom_keys:
+ if key in self.all_records:
+ rv[key] = self.all_records[key]
+ else:
+ self.logger.warning("SELinux %s %s customized, but no "
+ "record found. This may indicate an "
+ "error in your SELinux policy." %
+ (self.etype, key))
+ return rv
else:
# ValueError is really a pretty dumb exception to raise,
# but that's what the seobject customized() method raises
@@ -490,7 +500,8 @@ class SELinuxSeportHandler(SELinuxEntryHandler):
def _defaultargs(self, entry):
""" argument list for adding and modifying entries """
(port, proto) = entry.get("name").split("/")
- return (port, proto, '', entry.get("selinuxtype"))
+ return (port, proto, entry.get("mlsrange", ""),
+ entry.get("selinuxtype"))
def _deleteargs(self, entry):
return tuple(entry.get("name").split("/"))
@@ -512,14 +523,14 @@ class SELinuxSefcontextHandler(SELinuxEntryHandler):
char="-c",
door="-D")
filetypenames = dict(all="all files",
- regular="regular file",
- directory="directory",
- symlink="symbolic link",
- pipe="named pipe",
- socket="socket",
- block="block device",
- char="character device",
- door="door")
+ regular="regular file",
+ directory="directory",
+ symlink="symbolic link",
+ pipe="named pipe",
+ socket="socket",
+ block="block device",
+ char="character device",
+ door="door")
filetypeattrs = dict([v, k] for k, v in filetypenames.iteritems())
custom_re = re.compile(r'-f \'(?P<filetype>[a-z ]+)\'.*? \'(?P<name>.*)\'')
@@ -563,7 +574,7 @@ class SELinuxSefcontextHandler(SELinuxEntryHandler):
""" argument list for adding, modifying, and deleting entries """
return (entry.get("name"), entry.get("selinuxtype"),
self.filetypeargs[entry.get("filetype", "all")],
- '', '')
+ entry.get("mlsrange", ""), '')
def primarykey(self, entry):
return ":".join([entry.tag, entry.get("name"),
@@ -598,7 +609,7 @@ class SELinuxSenodeHandler(SELinuxEntryHandler):
def _defaultargs(self, entry):
""" argument list for adding, modifying, and deleting entries """
(addr, netmask) = entry.get("name").split("/")
- return (addr, netmask, entry.get("proto"), "",
+ return (addr, netmask, entry.get("proto"), entry.get("mlsrange", ""),
entry.get("selinuxtype"))
@@ -610,7 +621,8 @@ class SELinuxSeloginHandler(SELinuxEntryHandler):
def _defaultargs(self, entry):
""" argument list for adding, modifying, and deleting entries """
- return (entry.get("name"), entry.get("selinuxuser"), "")
+ return (entry.get("name"), entry.get("selinuxuser"),
+ entry.get("mlsrange", ""))
class SELinuxSeuserHandler(SELinuxEntryHandler):
@@ -650,15 +662,16 @@ class SELinuxSeuserHandler(SELinuxEntryHandler):
# prefix. see the comment in Install() above for more
# details.
rv = [entry.get("name"),
- entry.get("roles", "").replace(" ", ",").split(",")]
+ entry.get("roles", "").replace(" ", ",").split(","),
+ '', entry.get("mlsrange", "")]
if self.needs_prefix:
- rv.extend(['', '', entry.get("prefix")])
+ rv.append(entry.get("prefix"))
else:
key = self._key(entry)
if key in self.all_records:
attrs = self._key2attrs(key)
if attrs['prefix'] != entry.get("prefix"):
- rv.extend(['', '', entry.get("prefix")])
+ rv.append(entry.get("prefix"))
return tuple(rv)
@@ -670,7 +683,8 @@ class SELinuxSeinterfaceHandler(SELinuxEntryHandler):
def _defaultargs(self, entry):
""" argument list for adding, modifying, and deleting entries """
- return (entry.get("name"), '', entry.get("selinuxtype"))
+ return (entry.get("name"), entry.get("mlsrange", ""),
+ entry.get("selinuxtype"))
class SELinuxSepermissiveHandler(SELinuxEntryHandler):
diff --git a/src/lib/Bcfg2/Client/Tools/SMF.py b/src/lib/Bcfg2/Client/Tools/SMF.py
index 68d8b2965..8b23a4a37 100644
--- a/src/lib/Bcfg2/Client/Tools/SMF.py
+++ b/src/lib/Bcfg2/Client/Tools/SMF.py
@@ -48,12 +48,12 @@ class SMF(Bcfg2.Client.Tools.SvcTool):
gname = "/etc/rc*.d/%s" % filename
files = glob.glob(gname.replace('_', '.'))
if files:
- self.logger.debug("Matched %s with %s" % \
+ self.logger.debug("Matched %s with %s" %
(entry.get("FMRI"), ":".join(files)))
return entry.get('status') == 'on'
else:
- self.logger.debug("No service matching %s" % \
- (entry.get("FMRI")))
+ self.logger.debug("No service matching %s" %
+ entry.get("FMRI"))
return entry.get('status') == 'off'
try:
srvdata = \
@@ -76,13 +76,12 @@ class SMF(Bcfg2.Client.Tools.SvcTool):
if entry.get("FMRI").startswith('lrc'):
try:
loc = entry.get("FMRI")[4:].replace('_', '.')
- self.logger.debug("Renaming file %s to %s" % \
+ self.logger.debug("Renaming file %s to %s" %
(loc, loc.replace('/S', '/DISABLED.S')))
os.rename(loc, loc.replace('/S', '/DISABLED.S'))
return True
except OSError:
- self.logger.error("Failed to rename init script %s" % \
- (loc))
+ self.logger.error("Failed to rename init script %s" % loc)
return False
else:
return self.cmd.run("/usr/sbin/svcadm disable %s" %
@@ -118,12 +117,12 @@ class SMF(Bcfg2.Client.Tools.SvcTool):
def FindExtra(self):
"""Find Extra SMF Services."""
- allsrv = [name for name, version in \
- [srvc.split()
- for srvc in self.cmd.run([
- "/usr/bin/svcs", "-a", "-H",
- "-o", "FMRI,STATE"]).stdout.splitlines()]
- if version != 'disabled']
+ allsrv = []
+ for srvc in self.cmd.run(["/usr/bin/svcs", "-a", "-H",
+ "-o", "FMRI,STATE"]).stdout.splitlines():
+ name, version = srvc.split()
+ if version != 'disabled':
+ allsrv.append(name)
for svc in self.getSupportedEntries():
if svc.get("FMRI") in allsrv:
diff --git a/src/lib/Bcfg2/Client/Tools/SYSV.py b/src/lib/Bcfg2/Client/Tools/SYSV.py
index 38072c52e..aca7d593c 100644
--- a/src/lib/Bcfg2/Client/Tools/SYSV.py
+++ b/src/lib/Bcfg2/Client/Tools/SYSV.py
@@ -41,7 +41,7 @@ class SYSV(Bcfg2.Client.Tools.PkgTool):
self.noaskfile.write(noask)
# flush admin file contents to disk
self.noaskfile.flush()
- self.pkgtool = (self.pkgtool[0] % ("-a %s" % (self.noaskname)), \
+ self.pkgtool = (self.pkgtool[0] % ("-a %s" % (self.noaskname)),
self.pkgtool[1])
except: # pylint: disable=W0702
self.pkgtool = (self.pkgtool[0] % "", self.pkgtool[1])
@@ -66,7 +66,7 @@ class SYSV(Bcfg2.Client.Tools.PkgTool):
desired_version = entry.get('version')
if desired_version == 'any':
desired_version = self.installed.get(entry.get('name'),
- desired_version)
+ desired_version)
if not self.cmd.run(["/usr/bin/pkginfo", "-q", "-v",
desired_version, entry.get('name')]):
diff --git a/src/lib/Bcfg2/Client/Tools/Systemd.py b/src/lib/Bcfg2/Client/Tools/Systemd.py
index 027d91c71..20a172d3d 100644
--- a/src/lib/Bcfg2/Client/Tools/Systemd.py
+++ b/src/lib/Bcfg2/Client/Tools/Systemd.py
@@ -13,6 +13,8 @@ class Systemd(Bcfg2.Client.Tools.SvcTool):
__handles__ = [('Service', 'systemd')]
__req__ = {'Service': ['name', 'status']}
+ conflicts = ['Chkconfig']
+
def get_svc_command(self, service, action):
return "/bin/systemctl %s %s.service" % (action, service.get('name'))
diff --git a/src/lib/Bcfg2/Client/Tools/Upstart.py b/src/lib/Bcfg2/Client/Tools/Upstart.py
index cd1c4a2bc..c96eab69d 100644
--- a/src/lib/Bcfg2/Client/Tools/Upstart.py
+++ b/src/lib/Bcfg2/Client/Tools/Upstart.py
@@ -46,9 +46,9 @@ class Upstart(Bcfg2.Client.Tools.SvcTool):
entry.get('name'))
return False
- match = re.compile("%s( \(.*\))? (start|stop)/(running|waiting)" %
+ match = re.compile(r'%s( \(.*\))? (start|stop)/(running|waiting)' %
entry.get('name')).match(output)
- if match == None:
+ if match is None:
# service does not exist
entry.set('current_status', 'off')
status = False
diff --git a/src/lib/Bcfg2/Client/Tools/VCS.py b/src/lib/Bcfg2/Client/Tools/VCS.py
index 66e76f566..aca5dbbc7 100644
--- a/src/lib/Bcfg2/Client/Tools/VCS.py
+++ b/src/lib/Bcfg2/Client/Tools/VCS.py
@@ -1,14 +1,15 @@
"""VCS support."""
# TODO:
-# * git_write_index
# * add svn support
# * integrate properly with reports
missing = []
+import errno
import os
import shutil
import sys
+import stat
# python-dulwich git imports
try:
@@ -26,6 +27,38 @@ except ImportError:
import Bcfg2.Client.Tools
+def cleanup_mode(mode):
+ """Cleanup a mode value.
+
+ This will return a mode that can be stored in a tree object.
+
+ :param mode: Mode to clean up.
+ """
+ if stat.S_ISLNK(mode):
+ return stat.S_IFLNK
+ elif stat.S_ISDIR(mode):
+ return stat.S_IFDIR
+ elif dulwich.index.S_ISGITLINK(mode):
+ return dulwich.index.S_IFGITLINK
+ ret = stat.S_IFREG | int('644', 8)
+ ret |= (mode & int('111', 8))
+ return ret
+
+
+def index_entry_from_stat(stat_val, hex_sha, flags, mode=None):
+ """Create a new index entry from a stat value.
+
+ :param stat_val: POSIX stat_result instance
+ :param hex_sha: Hex sha of the object
+ :param flags: Index flags
+ """
+ if mode is None:
+ mode = cleanup_mode(stat_val.st_mode)
+ return (stat_val.st_ctime, stat_val.st_mtime, stat_val.st_dev,
+ stat_val.st_ino, mode, stat_val.st_uid,
+ stat_val.st_gid, stat_val.st_size, hex_sha, flags)
+
+
class VCS(Bcfg2.Client.Tools.Tool):
"""VCS support."""
__handles__ = [('Path', 'vcs')]
@@ -47,11 +80,24 @@ class VCS(Bcfg2.Client.Tools.Tool):
self.logger.info("Repository %s does not exist" %
entry.get('name'))
return False
- cur_rev = repo.head()
- if cur_rev != entry.get('revision'):
+ try:
+ expected_rev = entry.get('revision')
+ cur_rev = repo.head()
+ except:
+ return False
+
+ try:
+ client, path = dulwich.client.get_transport_and_path(entry.get('sourceurl'))
+ remote_refs = client.fetch_pack(path, (lambda x: None), None, None, None)
+ if expected_rev in remote_refs:
+ expected_rev = remote_refs[expected_rev]
+ except:
+ pass
+
+ if cur_rev != expected_rev:
self.logger.info("At revision %s need to go to revision %s" %
- (cur_rev, entry.get('revision')))
+ (cur_rev.strip(), expected_rev.strip()))
return False
return True
@@ -71,35 +117,47 @@ class VCS(Bcfg2.Client.Tools.Tool):
destname)
return False
- destr = dulwich.repo.Repo.init(destname, mkdir=True)
+ dulwich.file.ensure_dir_exists(destname)
+ destr = dulwich.repo.Repo.init(destname)
cl, host_path = dulwich.client.get_transport_and_path(entry.get('sourceurl'))
remote_refs = cl.fetch(host_path,
destr,
determine_wants=destr.object_store.determine_wants_all,
progress=sys.stdout.write)
- destr.refs['refs/heads/master'] = entry.get('revision')
- dtree = destr[entry.get('revision')].tree
- obj_store = destr.object_store
- for fname, mode, sha in obj_store.iter_tree_contents(dtree):
- fullpath = os.path.join(destname, fname)
- try:
- f = open(os.path.join(destname, fname), 'wb')
- except IOError:
- dir = os.path.split(fullpath)[0]
- os.makedirs(dir)
- f = open(os.path.join(destname, fname), 'wb')
- f.write(destr[sha].data)
- f.close()
- os.chmod(os.path.join(destname, fname), mode)
+
+ if entry.get('revision') in remote_refs:
+ destr.refs['HEAD'] = remote_refs[entry.get('revision')]
+ else:
+ destr.refs['HEAD'] = entry.get('revision')
+
+ dtree = destr['HEAD'].tree
+ index = dulwich.index.Index(destr.index_path())
+ for fname, mode, sha in destr.object_store.iter_tree_contents(dtree):
+ full_path = os.path.join(destname, fname)
+ dulwich.file.ensure_dir_exists(os.path.dirname(full_path))
+
+ if stat.S_ISLNK(mode):
+ src_path = destr[sha].as_raw_string()
+ try:
+ os.symlink(src_path, full_path)
+ except OSError:
+ e = sys.exc_info()[1]
+ if e.errno == errno.EEXIST:
+ os.unlink(full_path)
+ os.symlink(src_path, full_path)
+ else:
+ raise
+ else:
+ file = open(full_path, 'wb')
+ file.write(destr[sha].as_raw_string())
+ file.close()
+ os.chmod(full_path, mode)
+
+ st = os.lstat(full_path)
+ index[fname] = index_entry_from_stat(st, sha, 0)
+
+ index.write()
return True
- # FIXME: figure out how to write the git index properly
- #iname = "%s/.git/index" % entry.get('name')
- #f = open(iname, 'w+')
- #entries = obj_store[sha].iteritems()
- #try:
- # dulwich.index.write_index(f, entries)
- #finally:
- # f.close()
def Verifysvn(self, entry, _):
"""Verify svn repositories"""
diff --git a/src/lib/Bcfg2/Client/Tools/YUM.py b/src/lib/Bcfg2/Client/Tools/YUM.py
index c9fae7fc7..c30c0a13a 100644
--- a/src/lib/Bcfg2/Client/Tools/YUM.py
+++ b/src/lib/Bcfg2/Client/Tools/YUM.py
@@ -131,10 +131,12 @@ class YUM(Bcfg2.Client.Tools.PkgTool):
def __init__(self, logger, setup, config):
self.yumbase = self._loadYumBase(setup=setup, logger=logger)
Bcfg2.Client.Tools.PkgTool.__init__(self, logger, setup, config)
- self.ignores = [entry.get('name') for struct in config \
- for entry in struct \
- if entry.tag == 'Path' and \
- entry.get('type') == 'ignore']
+ self.ignores = []
+ for struct in config:
+ self.ignores.extend([entry.get('name')
+ for entry in struct
+ if (entry.tag == 'Path' and
+ entry.get('type') == 'ignore')])
self.instance_status = {}
self.extra_instances = []
self.modlists = {}
@@ -293,8 +295,8 @@ class YUM(Bcfg2.Client.Tools.PkgTool):
group. """
missing = Bcfg2.Client.Tools.PkgTool.missing_attrs(self, entry)
- if entry.get('name', None) == None and \
- entry.get('group', None) == None:
+ if (entry.get('name', None) is None and
+ entry.get('group', None) is None):
missing += ['name', 'group']
return missing
@@ -422,10 +424,10 @@ class YUM(Bcfg2.Client.Tools.PkgTool):
if entry.get('group'):
self.logger.debug("Verifying packages for group %s" %
- entry.get('group'))
+ entry.get('group'))
else:
self.logger.debug("Verifying package instances for %s" %
- entry.get('name'))
+ entry.get('name'))
self.verify_cache = dict() # Used for checking multilib packages
self.modlists[entry] = modlist
@@ -434,10 +436,10 @@ class YUM(Bcfg2.Client.Tools.PkgTool):
package_fail = False
qtext_versions = []
virt_pkg = False
- pkg_checks = self.pkg_checks and \
- entry.get('pkg_checks', 'true').lower() == 'true'
- pkg_verify = self.pkg_verify and \
- entry.get('pkg_verify', 'true').lower() == 'true'
+ pkg_checks = (self.pkg_checks and
+ 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':
@@ -455,15 +457,13 @@ class YUM(Bcfg2.Client.Tools.PkgTool):
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]
+ 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]
+ 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"))
@@ -489,7 +489,7 @@ class YUM(Bcfg2.Client.Tools.PkgTool):
else:
all_pkg_objs = \
self.yumbase.rpmdb.searchNevra(name=entry.get('name'))
- if len(all_pkg_objs) == 0 and yum_group != True:
+ if len(all_pkg_objs) == 0 and yum_group is not 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:
@@ -567,9 +567,9 @@ class YUM(Bcfg2.Client.Tools.PkgTool):
pkg_objs = [po for po in all_pkg_objs]
else:
pkg_objs = [po for po in all_pkg_objs
- if po.checkPrco('provides',
- (nevra["name"], 'EQ',
- tuple(vlist)))]
+ if po.checkPrco('provides',
+ (nevra["name"], 'EQ',
+ tuple(vlist)))]
elif entry.get('name') == 'gpg-pubkey':
if 'version' not in nevra:
self.logger.warning("Skipping verify: gpg-pubkey without "
@@ -622,7 +622,7 @@ class YUM(Bcfg2.Client.Tools.PkgTool):
if self.setup.get('quick', False):
# Passed -q on the command line
continue
- if not (pkg_verify and \
+ if not (pkg_verify and
inst.get('pkg_verify', 'true').lower() == 'true'):
continue
@@ -648,8 +648,8 @@ class YUM(Bcfg2.Client.Tools.PkgTool):
# Now take out the Yum specific objects / modlists / unproblems
ignores = [ig.get('name') for ig in entry.findall('Ignore')] + \
- [ig.get('name') for ig in inst.findall('Ignore')] + \
- self.ignores
+ [ig.get('name') for ig in inst.findall('Ignore')] + \
+ self.ignores
for fname, probs in list(vrfy_result.items()):
if fname in modlist:
self.logger.debug(" %s in modlist, skipping" % fname)
@@ -737,8 +737,9 @@ class YUM(Bcfg2.Client.Tools.PkgTool):
for pkg in pkg_objs:
self.logger.debug(" Extra Instance Found: %s" % str(pkg))
Bcfg2.Client.XML.SubElement(extra_entry, 'Instance',
- epoch=pkg.epoch, name=pkg.name, version=pkg.version,
- release=pkg.release, arch=pkg.arch)
+ epoch=pkg.epoch, name=pkg.name,
+ version=pkg.version,
+ release=pkg.release, arch=pkg.arch)
if pkg_objs == []:
return None
@@ -782,7 +783,7 @@ class YUM(Bcfg2.Client.Tools.PkgTool):
ver = yum.misc.keyIdToRPMVer(gpg['keyid'])
rel = yum.misc.keyIdToRPMVer(gpg['timestamp'])
if not (ver == inst.get('version') and rel == inst.get('release')):
- self.logger.info("GPG key file %s does not match gpg-pubkey-%s-%s"\
+ self.logger.info("GPG key file %s does not match gpg-pubkey-%s-%s"
% (key_file, inst.get('version'),
inst.get('release')))
return False
@@ -791,20 +792,21 @@ class YUM(Bcfg2.Client.Tools.PkgTool):
gpg['timestamp']) == 0:
result = tset.pgpImportPubkey(yum.misc.procgpgkey(rawkey))
else:
- self.logger.debug("gpg-pubkey-%s-%s already installed"\
- % (inst.get('version'),
- inst.get('release')))
+ self.logger.debug("gpg-pubkey-%s-%s already installed" %
+ (inst.get('version'), inst.get('release')))
return True
if result != 0:
- self.logger.debug("Unable to install %s-%s" % \
- (self.instance_status[inst].get('pkg').get('name'),
- nevra2string(inst)))
+ self.logger.debug(
+ "Unable to install %s-%s" %
+ (self.instance_status[inst].get('pkg').get('name'),
+ nevra2string(inst)))
return False
else:
- self.logger.debug("Installed %s-%s-%s" % \
- (self.instance_status[inst].get('pkg').get('name'),
- inst.get('version'), inst.get('release')))
+ self.logger.debug(
+ "Installed %s-%s-%s" %
+ (self.instance_status[inst].get('pkg').get('name'),
+ inst.get('version'), inst.get('release')))
return True
def _runYumTransaction(self):
@@ -898,7 +900,7 @@ class YUM(Bcfg2.Client.Tools.PkgTool):
# Remove extra instances.
# Can not reverify because we don't have a package entry.
if self.extra_instances is not None and len(self.extra_instances) > 0:
- if (self.setup.get('remove') == 'all' or \
+ if (self.setup.get('remove') == 'all' or
self.setup.get('remove') == 'packages'):
self.Remove(self.extra_instances)
else:
@@ -913,7 +915,7 @@ class YUM(Bcfg2.Client.Tools.PkgTool):
# Figure out which instances of the packages actually need something
# doing to them and place in the appropriate work 'queue'.
for pkg in packages:
- insts = [pinst for pinst in pkg \
+ insts = [pinst for pinst in pkg
if pinst.tag in ['Instance', 'Package']]
if insts:
for inst in insts:
@@ -1006,10 +1008,11 @@ class YUM(Bcfg2.Client.Tools.PkgTool):
if not self.setup['kevlar']:
for pkg_entry in [p for p in packages if self.canVerify(p)]:
- self.logger.debug("Reverifying Failed Package %s" \
- % (pkg_entry.get('name')))
- states[pkg_entry] = self.VerifyPackage(pkg_entry,
- self.modlists.get(pkg_entry, []))
+ self.logger.debug("Reverifying Failed Package %s" %
+ pkg_entry.get('name'))
+ states[pkg_entry] = \
+ self.VerifyPackage(pkg_entry,
+ self.modlists.get(pkg_entry, []))
for entry in [ent for ent in packages if states[ent]]:
self.modified.append(entry)
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.