summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSol Jerome <sol.jerome@gmail.com>2010-10-18 11:43:37 -0500
committerSol Jerome <sol.jerome@gmail.com>2010-10-18 11:46:55 -0500
commit8a70dbabd08308403ad8296979f50c379c707df9 (patch)
tree37d9604b3c6132b1c71622c8cd7cda319dab76c1
parent16807d819b63384a0f588b4ea881c7b043571875 (diff)
downloadbcfg2-8a70dbabd08308403ad8296979f50c379c707df9.tar.gz
bcfg2-8a70dbabd08308403ad8296979f50c379c707df9.tar.bz2
bcfg2-8a70dbabd08308403ad8296979f50c379c707df9.zip
POSIX: Remove client-side support for old POSIX types
Signed-off-by: Sol Jerome <sol.jerome@gmail.com>
-rw-r--r--schemas/rules.xsd26
-rw-r--r--src/lib/Client/Frame.py14
-rw-r--r--src/lib/Client/Tools/APT.py2
-rw-r--r--src/lib/Client/Tools/POSIX.py636
-rw-r--r--src/lib/Client/Tools/YUMng.py2
-rw-r--r--src/lib/Client/Tools/__init__.py3
-rw-r--r--src/lib/Server/Admin/Bundle.py2
-rw-r--r--src/lib/Server/Plugins/POSIXCompat.py38
-rw-r--r--src/lib/Server/Plugins/__init__.py1
-rwxr-xr-xsrc/sbin/bcfg2-repo-validate41
10 files changed, 355 insertions, 410 deletions
diff --git a/schemas/rules.xsd b/schemas/rules.xsd
index 207eb65e5..80036834a 100644
--- a/schemas/rules.xsd
+++ b/schemas/rules.xsd
@@ -54,14 +54,6 @@
<xsd:attribute name='verify_flags' type='xsd:string'/>
</xsd:complexType>
- <xsd:complexType name='DirectoryType'>
- <xsd:attribute type='xsd:string' name='name' use='required'/>
- <xsd:attribute type='xsd:string' name='perms'/>
- <xsd:attribute type='xsd:string' name='owner'/>
- <xsd:attribute type='xsd:string' name='group'/>
- <xsd:attribute type='xsd:string' name='prune'/>
- </xsd:complexType>
-
<xsd:complexType name='ActionType'>
<xsd:attribute type='ActionTimingEnum' name='timing' use='required'/>
<xsd:attribute type='ActionWhenEnum' name='when' use='required'/>
@@ -70,11 +62,6 @@
<xsd:attribute type='xsd:string' name='command' use='required'/>
</xsd:complexType>
- <xsd:complexType name='SymLinkType'>
- <xsd:attribute type='xsd:string' name='name' use='required'/>
- <xsd:attribute type='xsd:string' name='to' use='required'/>
- </xsd:complexType>
-
<xsd:complexType name='PathType'>
<xsd:attribute type='PathTypeEnum' name='type' use='required'/>
<xsd:attribute type='xsd:string' name='name' use='required'/>
@@ -89,21 +76,11 @@
<xsd:attribute type='xsd:string' name='to'/>
</xsd:complexType>
- <xsd:complexType name='PermissionsType'>
- <xsd:attribute type='xsd:string' name='name' use='required'/>
- <xsd:attribute type='xsd:string' name='perms' use='required'/>
- <xsd:attribute type='xsd:string' name='owner' use='required'/>
- <xsd:attribute type='xsd:string' name='group' use='required'/>
- </xsd:complexType>
-
<xsd:complexType name='RContainerType'>
<xsd:choice minOccurs='0' maxOccurs='unbounded'>
<xsd:element name='Service' type='ServiceType'/>
- <xsd:element name='Directory' type='DirectoryType'/>
- <xsd:element name='SymLink' type='SymLinkType'/>
<xsd:element name='Package' type='PackageType'/>
<xsd:element name='Path' type='PathType'/>
- <xsd:element name='Permissions' type='PermissionsType'/>
<xsd:element name='Action' type='ActionType'/>
<xsd:element name='Group' type='RContainerType'/>
<xsd:element name='Client' type='RContainerType'/>
@@ -117,11 +94,8 @@
<xsd:complexType>
<xsd:choice minOccurs='0' maxOccurs='unbounded'>
<xsd:element name='Service' type='ServiceType'/>
- <xsd:element name='Directory' type='DirectoryType'/>
- <xsd:element name='SymLink' type='SymLinkType'/>
<xsd:element name='Package' type='PackageType'/>
<xsd:element name='Path' type='PathType'/>
- <xsd:element name='Permissions' type='PermissionsType'/>
<xsd:element name='Action' type='ActionType'/>
<xsd:element name='Group' type='RContainerType'/>
<xsd:element name='Client' type='RContainerType'/>
diff --git a/src/lib/Client/Frame.py b/src/lib/Client/Frame.py
index 6cfb19732..545d4b584 100644
--- a/src/lib/Client/Frame.py
+++ b/src/lib/Client/Frame.py
@@ -110,20 +110,6 @@ class Frame:
self.logger.info("Loaded tool drivers:")
self.logger.info([tool.name for tool in self.tools])
if not self.dryrun and not self.setup['bundle']:
- for cfile in [cfl for cfl in config.findall(".//ConfigFile") \
- if cfl.get('name') in self.__important__]:
- tl = [t for t in self.tools if t.handlesEntry(cfile) \
- and t.canVerify(cfile)]
- if tl:
- if not tl[0].VerifyConfigFile(cfile, []):
- if self.setup['interactive'] and not \
- promptFilter("Install %s: %s? (y/N):", [cfile]):
- continue
- try:
- self.states[cfile] = tl[0].InstallConfigFile(cfile)
- except:
- self.logger.error("Unexpected tool failure",
- exc_info=1)
for cfile in [cfl for cfl in config.findall(".//Path") \
if cfl.get('name') in self.__important__ and \
cfl.get('type') == 'file']:
diff --git a/src/lib/Client/Tools/APT.py b/src/lib/Client/Tools/APT.py
index 9dc2c5bba..2afe2eab7 100644
--- a/src/lib/Client/Tools/APT.py
+++ b/src/lib/Client/Tools/APT.py
@@ -55,7 +55,7 @@ class APT(Bcfg2.Client.Tools.Tool):
'%s/apt/apt.conf' % etc_path,
'%s/dpkg/dpkg.cfg' % etc_path] + \
[entry.get('name') for struct in config for entry in struct \
- if entry.tag in ['Path', 'ConfigFile'] and \
+ if entry.tag == 'Path' and \
entry.get('name').startswith('%s/apt/sources.list' % etc_path)]
self.nonexistent = [entry.get('name') for struct in config for entry in struct \
if entry.tag == 'Path' and entry.get('type') == 'nonexistent']
diff --git a/src/lib/Client/Tools/POSIX.py b/src/lib/Client/Tools/POSIX.py
index a4417297a..d2611130c 100644
--- a/src/lib/Client/Tools/POSIX.py
+++ b/src/lib/Client/Tools/POSIX.py
@@ -1,11 +1,11 @@
"""All POSIX Type client support for Bcfg2."""
__revision__ = '$Revision$'
-from datetime import datetime
from stat import S_ISVTX, S_ISGID, S_ISUID, S_IXUSR, S_IWUSR, S_IRUSR, S_IXGRP
from stat import S_IWGRP, S_IRGRP, S_IXOTH, S_IWOTH, S_IROTH, ST_MODE, S_ISDIR
from stat import S_IFREG, ST_UID, ST_GID, S_ISREG, S_IFDIR, S_ISLNK, ST_MTIME
import binascii
+from datetime import datetime
import difflib
import errno
import grp
@@ -14,7 +14,6 @@ import os
import pwd
import shutil
import stat
-import string
import time
import Bcfg2.Client.Tools
import Bcfg2.Options
@@ -45,21 +44,6 @@ def calcPerms(initial, perms):
return tempperms
-def normUid(entry):
- """
- This takes a user name or uid and
- returns the corresponding uid or False.
- """
- try:
- try:
- return int(entry.get('owner'))
- except:
- return int(pwd.getpwnam(entry.get('owner'))[2])
- except (OSError, KeyError):
- log.error('UID normalization failed for %s' % (entry.get('name')))
- return False
-
-
def normGid(entry):
"""
This takes a group name or gid and
@@ -74,40 +58,33 @@ def normGid(entry):
log.error('GID normalization failed for %s' % (entry.get('name')))
return False
-text_chars = "".join([chr(y) for y in range(32, 127)] + list("\n\r\t\b"))
-notrans = string.maketrans("", "")
-
-def isString(strng):
- """Returns true if a string contains no binary chars."""
- if "\0" in strng:
+def normUid(entry):
+ """
+ This takes a user name or uid and
+ returns the corresponding uid or False.
+ """
+ try:
+ try:
+ return int(entry.get('owner'))
+ except:
+ return int(pwd.getpwnam(entry.get('owner'))[2])
+ except (OSError, KeyError):
+ log.error('UID normalization failed for %s' % (entry.get('name')))
return False
- if not strng:
- return True
-
- return len(strng.translate(notrans, text_chars)) == 0
-
class POSIX(Bcfg2.Client.Tools.Tool):
"""POSIX File support code."""
name = 'POSIX'
- __handles__ = [('ConfigFile', None),
- ('Directory', None),
- ('Path', 'device'),
+ __handles__ = [('Path', 'device'),
('Path', 'directory'),
('Path', 'file'),
('Path', 'hardlink'),
('Path', 'nonexistent'),
('Path', 'permissions'),
- ('Path', 'symlink'),
- ('Permissions', None),
- ('SymLink', None)]
- __req__ = {'ConfigFile': ['name', 'owner', 'group', 'perms'],
- 'Directory': ['name', 'owner', 'group', 'perms'],
- 'Path': ['name', 'type'],
- 'Permissions': ['name', 'owner', 'group', 'perms'],
- 'SymLink': ['name', 'to']}
+ ('Path', 'symlink')]
+ __req__ = {'Path': ['name', 'type']}
# grab paranoid options from /etc/bcfg2.conf
opts = {'ppath': Bcfg2.Options.PARANOID_PATH,
@@ -120,64 +97,150 @@ class POSIX(Bcfg2.Client.Tools.Tool):
def canInstall(self, entry):
"""Check if entry is complete for installation."""
if Bcfg2.Client.Tools.Tool.canInstall(self, entry):
- if (entry.tag, entry.text, entry.get('empty', 'false')) == \
- ('ConfigFile', None, 'false'):
+ if (entry.tag,
+ entry.get('type'),
+ entry.text,
+ entry.get('empty', 'false')) == ('Path',
+ 'file',
+ None,
+ 'false'):
return False
return True
else:
return False
- def VerifySymLink(self, entry, _):
- """Verify SymLink Entry."""
- try:
- sloc = os.readlink(entry.get('name'))
- if sloc == entry.get('to'):
- return True
- self.logger.debug("Symlink %s points to %s, should be %s" % \
- (entry.get('name'), sloc, entry.get('to')))
- entry.set('current_to', sloc)
- entry.set('qtext', "Link %s to %s? [y/N] " % (entry.get('name'),
- entry.get('to')))
+ def gatherCurrentData(self, entry):
+ if entry.tag == 'Path' and entry.get('type') == 'file':
+ try:
+ ondisk = os.stat(entry.get('name'))
+ except OSError:
+ entry.set('current_exists', 'false')
+ self.logger.debug("%s %s does not exist" %
+ (entry.tag, entry.get('name')))
+ return False
+ try:
+ entry.set('current_owner', str(ondisk[ST_UID]))
+ entry.set('current_group', str(ondisk[ST_GID]))
+ except (OSError, KeyError):
+ pass
+ entry.set('perms', str(oct(ondisk[ST_MODE])[-4:]))
+ try:
+ content = open(entry.get('name')).read()
+ entry.set('current_bfile', binascii.b2a_base64(content))
+ except IOError, error:
+ self.logger.error("Failed to read %s: %s" % (error.filename,
+ error.strerror))
+
+ def Verifydevice(self, entry, _):
+ """Verify device entry."""
+ if entry.get('dev_type') == None or \
+ entry.get('owner') == None or \
+ entry.get('group') == None:
+ self.logger.error('Entry %s not completely specified. '
+ 'Try running bcfg2-repo-validate.' % (entry.get('name')))
return False
+ 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:
+ self.logger.error('Entry %s not completely specified. '
+ 'Try running bcfg2-repo-validate.' % (entry.get('name')))
+ return False
+ try:
+ # check for file existence
+ filestat = os.stat(entry.get('name'))
except OSError:
entry.set('current_exists', 'false')
- entry.set('qtext', "Link %s to %s? [y/N] " % (entry.get('name'),
- entry.get('to')))
+ self.logger.debug("%s %s does not exist" %
+ (entry.tag, entry.get('name')))
return False
- def InstallSymLink(self, entry):
- """Install SymLink entry."""
- self.logger.info("Installing Symlink %s" % (entry.get('name')))
- if os.path.lexists(entry.get('name')):
- try:
- fmode = os.lstat(entry.get('name'))[ST_MODE]
- if S_ISREG(fmode) or S_ISLNK(fmode):
- self.logger.debug("Non-directory entry already exists at "
- "%s. Unlinking entry." % \
- (entry.get('name')))
- os.unlink(entry.get('name'))
- elif S_ISDIR(fmode):
- self.logger.debug("Directory entry already exists at %s" %\
- (entry.get('name')))
- self.cmd.run("mv %s/ %s.bak" % \
- (entry.get('name'),
- entry.get('name')))
- else:
- os.unlink(entry.get('name'))
- except OSError:
- self.logger.info("Symlink %s cleanup failed" %\
- (entry.get('name')))
try:
- os.symlink(entry.get('to'), entry.get('name'))
- return True
+ # attempt to verify device properties as specified in config
+ dev_type = entry.get('dev_type')
+ mode = calcPerms(device_map[dev_type],
+ entry.get('mode', '0600'))
+ owner = normUid(entry)
+ group = normGid(entry)
+ if dev_type in ['block', 'char']:
+ # check for incompletely specified entries
+ if entry.get('major') == None or \
+ entry.get('minor') == None:
+ self.logger.error('Entry %s not completely specified. '
+ 'Try running bcfg2-repo-validate.' % (entry.get('name')))
+ return False
+ major = int(entry.get('major'))
+ minor = int(entry.get('minor'))
+ if major == os.major(filestat.st_rdev) and \
+ minor == os.minor(filestat.st_rdev) and \
+ mode == filestat.st_mode and \
+ owner == filestat.st_uid and \
+ group == filestat.st_gid:
+ return True
+ else:
+ return False
+ elif dev_type == 'fifo' and \
+ mode == filestat.st_mode and \
+ owner == filestat.st_uid and \
+ group == filestat.st_gid:
+ return True
+ else:
+ self.logger.info('Device properties for %s incorrect' % \
+ entry.get('name'))
+ return False
except OSError:
+ self.logger.debug("%s %s failed to verify" %
+ (entry.tag, entry.get('name')))
return False
- def VerifyDirectory(self, entry, modlist):
- """Verify Directory entry."""
+ def Installdevice(self, entry):
+ """Install device entries."""
+ try:
+ # check for existing paths and remove them
+ os.lstat(entry.get('name'))
+ try:
+ os.unlink(entry.get('name'))
+ exists = False
+ except OSError:
+ self.logger.info('Failed to unlink %s' % \
+ entry.get('name'))
+ return False
+ except OSError:
+ exists = False
+
+ if not exists:
+ try:
+ dev_type = entry.get('dev_type')
+ mode = calcPerms(device_map[dev_type],
+ entry.get('mode', '0600'))
+ if dev_type in ['block', 'char']:
+ # check if major/minor are properly specified
+ if entry.get('major') == None or \
+ entry.get('minor') == None:
+ self.logger.error('Entry %s not completely specified. '
+ 'Try running bcfg2-repo-validate.' % (entry.get('name')))
+ return False
+ major = int(entry.get('major'))
+ minor = int(entry.get('minor'))
+ device = os.makedev(major, minor)
+ os.mknod(entry.get('name'), mode, device)
+ else:
+ os.mknod(entry.get('name'), mode)
+ os.chown(entry.get('name'), normUid(entry), normGid(entry))
+ return True
+ except KeyError:
+ self.logger.error('Failed to install %s' % entry.get('name'))
+ except OSError:
+ self.logger.error('Failed to install %s' % entry.get('name'))
+ return False
+
+ def Verifydirectory(self, entry, modlist):
+ """Verify Path type='directory' entry."""
if entry.get('perms') == None or \
entry.get('owner') == None or \
entry.get('group') == None:
+ self.logger.error('Entry %s not completely specified. '
+ 'Try running bcfg2-repo-validate.' % (entry.get('name')))
return False
while len(entry.get('perms', '')) < 4:
entry.set('perms', '0' + entry.get('perms', ''))
@@ -210,9 +273,8 @@ class POSIX(Bcfg2.Client.Tools.Tool):
pruneTrue = True
ex_ents = []
if entry.get('prune', 'false') == 'true' \
- and (entry.tag == 'Directory' or
- entry.get('type') == 'directory'):
- # FIXME: need to verify both old and new POSIX types
+ and (entry.tag == 'Path' and entry.get('type') == 'directory'):
+ # check for any extra entries when prune='true' attribute is set
try:
entries = ['/'.join([entry.get('name'), ent]) \
for ent in os.listdir(entry.get('name'))]
@@ -227,7 +289,8 @@ class POSIX(Bcfg2.Client.Tools.Tool):
entry.get('name')
nqtext += ":".join(ex_ents)
entry.set('qtest', nqtext)
- [entry.append(XML.Element('Prune', path=x)) for x in ex_ents]
+ [entry.append(XML.Element('Prune', path=x)) \
+ for x in ex_ents]
except OSError:
ex_ents = []
pruneTrue = True
@@ -243,7 +306,8 @@ class POSIX(Bcfg2.Client.Tools.Tool):
entry.set('qtext', nqtext)
if group != str(normGid(entry)):
entry.set('current_group', group)
- self.logger.debug("%s %s group wrong" % (entry.tag, entry.get('name')))
+ self.logger.debug("%s %s group wrong" % \
+ (entry.tag, entry.get('name')))
nqtext = entry.get('qtext', '') + '\n'
nqtext += "%s group is %s should be %s" % \
(entry.get('name'), group, entry.get('group'))
@@ -251,10 +315,16 @@ class POSIX(Bcfg2.Client.Tools.Tool):
if perms != entry.get('perms'):
entry.set('current_perms', perms)
self.logger.debug("%s %s permissions are %s should be %s" %
- (entry.tag, entry.get('name'), perms, entry.get('perms')))
+ (entry.tag,
+ entry.get('name'),
+ perms,
+ entry.get('perms')))
nqtext = entry.get('qtext', '') + '\n'
- nqtext += "%s perms are %s should be %s" % \
- (entry.get('name'), perms, entry.get('perms'))
+ nqtext += "%s %s perms are %s should be %s" % \
+ (entry.tag,
+ entry.get('name'),
+ perms,
+ entry.get('perms'))
entry.set('qtext', nqtext)
if mtime != entry.get('mtime', '-1'):
entry.set('current_mtime', mtime)
@@ -265,21 +335,23 @@ class POSIX(Bcfg2.Client.Tools.Tool):
nqtext += "%s mtime is %s should be %s" % \
(entry.get('name'), mtime, entry.get('mtime'))
entry.set('qtext', nqtext)
- if entry.tag != 'ConfigFile':
+ if entry.get('type') != 'file':
nnqtext = entry.get('qtext')
- nnqtext += '\nInstall %s %s: (y/N) ' % (entry.tag, entry.get('name'))
+ nnqtext += '\nInstall %s %s: (y/N) ' % (entry.get('type'),
+ entry.get('name'))
entry.set('qtext', nnqtext)
return pTrue and pruneTrue
- def InstallDirectory(self, entry):
- """Install Directory entry."""
+ def Installdirectory(self, entry):
+ """Install Path type='directory' entry."""
if entry.get('perms') == None or \
entry.get('owner') == None or \
entry.get('group') == None:
self.logger.error('Entry %s not completely specified. '
- 'Try running bcfg2-repo-validate.' % (entry.get('name')))
+ 'Try running bcfg2-repo-validate.' % \
+ (entry.get('name')))
return False
- self.logger.info("Installing Directory %s" % (entry.get('name')))
+ self.logger.info("Installing directory %s" % (entry.get('name')))
try:
fmode = os.lstat(entry.get('name'))
if not S_ISDIR(fmode[ST_MODE]):
@@ -289,7 +361,8 @@ class POSIX(Bcfg2.Client.Tools.Tool):
os.unlink(entry.get('name'))
exists = False
except OSError:
- self.logger.info("Failed to unlink %s" % (entry.get('name')))
+ self.logger.info("Failed to unlink %s" % \
+ (entry.get('name')))
return False
else:
self.logger.debug("Found a pre-existing directory at %s" % \
@@ -334,7 +407,8 @@ class POSIX(Bcfg2.Client.Tools.Tool):
pname = pent.get('path')
ulfailed = False
if os.path.isdir(pname):
- self.logger.info("Not removing extra directory %s, please check and remove manually" % pname)
+ self.logger.info("Not removing extra directory %s, "
+ "please check and remove manually" % pname)
continue
try:
self.logger.debug("Unlinking file %s" % pname)
@@ -344,188 +418,12 @@ class POSIX(Bcfg2.Client.Tools.Tool):
ulfailed = True
if ulfailed:
return False
- return self.InstallPermissions(entry)
-
- def VerifyhardLink(self, entry, _):
- """Verify HardLink entry."""
- try:
- if os.path.samefile(entry.get('name'), entry.get('to')):
- return True
- self.logger.debug("Hardlink %s is incorrect" % \
- entry.get('name'))
- entry.set('qtext', "Link %s to %s? [y/N] " % \
- (entry.get('name'),
- entry.get('to')))
- return False
- except OSError:
- entry.set('current_exists', 'false')
- entry.set('qtext', "Link %s to %s? [y/N] " % \
- (entry.get('name'),
- entry.get('to')))
- return False
-
- def InstallhardLink(self, entry):
- """Install HardLink entry."""
- self.logger.info("Installing Hardlink %s" % (entry.get('name')))
- if os.path.lexists(entry.get('name')):
- try:
- fmode = os.lstat(entry.get('name'))[ST_MODE]
- if S_ISREG(fmode) or S_ISLNK(fmode):
- self.logger.debug("Non-directory entry already exists at "
- "%s. Unlinking entry." % (entry.get('name')))
- os.unlink(entry.get('name'))
- elif S_ISDIR(fmode):
- self.logger.debug("Directory entry already exists at %s" % \
- (entry.get('name')))
- self.cmd.run("mv %s/ %s.bak" % \
- (entry.get('name'),
- entry.get('name')))
- else:
- os.unlink(entry.get('name'))
- except OSError:
- self.logger.info("Hardlink %s cleanup failed" % (entry.get('name')))
- try:
- os.link(entry.get('to'), entry.get('name'))
- return True
- except OSError:
- return False
-
- def VerifyPermissions(self, entry, _):
- """Verify Permissions entry"""
- return self.VerifyDirectory(entry, _)
-
- def InstallPermissions(self, entry):
- """Install POSIX permissions"""
- if entry.get('perms') == None or \
- entry.get('owner') == None or \
- entry.get('group') == None:
- self.logger.error('Entry %s not completely specified. '
- 'Try running bcfg2-repo-validate.' % (entry.get('name')))
- return False
- try:
- os.chown(entry.get('name'), normUid(entry), normGid(entry))
- os.chmod(entry.get('name'), calcPerms(S_IFDIR, entry.get('perms')))
- return True
- except (OSError, KeyError):
- self.logger.error('Permission fixup failed for %s' % \
- (entry.get('name')))
- return False
-
- def Verifydevice(self, entry, _):
- """Verify device entry."""
- try:
- # check for file existence
- filestat = os.stat(entry.get('name'))
- except OSError:
- entry.set('current_exists', 'false')
- self.logger.debug("%s %s does not exist" %
- (entry.tag, entry.get('name')))
- return False
-
- try:
- # attempt to verify device properties as specified in config
- dev_type = entry.get('dev_type')
- mode = calcPerms(device_map[dev_type],
- entry.get('mode', '0600'))
- owner = entry.get('owner')
- group = entry.get('group')
- if dev_type in ['block', 'char']:
- major = int(entry.get('major'))
- minor = int(entry.get('minor'))
- if major == os.major(filestat.st_rdev) and \
- minor == os.minor(filestat.st_rdev) and \
- mode == filestat.st_mode and \
- owner == filestat.st_uid and \
- group == filestat.st_gid:
- return True
- else:
- return False
- elif dev_type == 'fifo' and \
- mode == filestat.st_mode and \
- owner == filestat.st_uid and \
- group == filestat.st_gid:
- return True
- else:
- self.logger.info('Device properties for %s incorrect' % \
- entry.get('name'))
- return False
- except OSError:
- self.logger.debug("%s %s failed to verify" %
- (entry.tag, entry.get('name')))
- return False
-
- def Installdevice(self, entry):
- """Install device entries."""
- try:
- # check for existing paths and remove them
- filestat = os.lstat(entry.get('name'))
- try:
- os.unlink(entry.get('name'))
- exists = False
- except OSError:
- self.logger.info('Failed to unlink %s' % \
- entry.get('name'))
- return False
- except OSError:
- exists = False
-
- if not exists:
- try:
- dev_type = entry.get('dev_type')
- mode = calcPerms(device_map[dev_type],
- entry.get('mode', '0600'))
- if dev_type in ['block', 'char']:
- major = int(entry.get('major'))
- minor = int(entry.get('minor'))
- device = os.makedev(major, minor)
- os.mknod(entry.get('name'), mode, device)
- else:
- os.mknod(entry.get('name'), mode)
- os.chown(entry.get('name'), normUid(entry), normGid(entry))
- return True
- except OSError:
- self.logger.error('Failed to install %s' % entry.get('name'))
- return False
+ return self.Installpermissions(entry)
- def Verifynonexistent(self, entry, _):
- """Verify nonexistent entry."""
- # return true if path does _not_ exist
- return not os.path.lexists(entry.get('name'))
-
- def Installnonexistent(self, entry):
- '''Remove nonexistent entries'''
- try:
- os.remove(entry.get('name'))
- return True
- except OSError:
- self.logger.error('Failed to remove %s' % entry.get('name'))
- return False
-
- def gatherCurrentData(self, entry):
- if entry.tag == 'ConfigFile':
- try:
- ondisk = os.stat(entry.get('name'))
- except OSError:
- entry.set('current_exists', 'false')
- self.logger.debug("%s %s does not exist" %
- (entry.tag, entry.get('name')))
- return False
- try:
- entry.set('current_owner', str(ondisk[ST_UID]))
- entry.set('current_group', str(ondisk[ST_GID]))
- except (OSError, KeyError):
- pass
- entry.set('perms', str(oct(ondisk[ST_MODE])[-4:]))
- try:
- content = open(entry.get('name')).read()
- entry.set('current_bfile', binascii.b2a_base64(content))
- except IOError, error:
- self.logger.error("Failed to read %s: %s" % (error.filename, error.strerror))
-
- def VerifyConfigFile(self, entry, _):
- """Install ConfigFile entry."""
- # configfile verify is permissions check + content check
- permissionStatus = self.VerifyDirectory(entry, _)
+ def Verifyfile(self, entry, _):
+ """Verify Path type='file' entry."""
+ # permissions check + content check
+ permissionStatus = self.Verifydirectory(entry, _)
tbin = False
if entry.get('encoding', 'ascii') == 'base64':
tempdata = binascii.a2b_base64(entry.text)
@@ -534,8 +432,8 @@ class POSIX(Bcfg2.Client.Tools.Tool):
tempdata = ''
else:
if entry.text == None:
- self.logger.error("Cannot verify incomplete ConfigFile %s" % \
- (entry.get('name')))
+ self.logger.error("Cannot verify incomplete Path type='%s' %s" % \
+ (entry.get('type'), entry.get('name')))
return False
tempdata = entry.text
if type(tempdata) == unicode:
@@ -558,7 +456,12 @@ class POSIX(Bcfg2.Client.Tools.Tool):
# md5sum so it would be faster for big binary files
contentStatus = content == tempdata
if not contentStatus:
- if tbin or not isString(content):
+ try:
+ content.decode('ascii')
+ isstring = True
+ except:
+ isstring = False
+ if tbin or not isstring:
entry.set('current_bfile', binascii.b2a_base64(content))
nqtext = entry.get('qtext', '')
nqtext += '\nBinary file, no printable diff'
@@ -567,7 +470,8 @@ class POSIX(Bcfg2.Client.Tools.Tool):
rawdiff = []
start = time.time()
longtime = False
- for x in difflib.ndiff(content.split('\n'), tempdata.split('\n')):
+ for x in difflib.ndiff(content.split('\n'),
+ tempdata.split('\n')):
now = time.time()
rawdiff.append(x)
if now - start > 5 and not longtime:
@@ -606,9 +510,9 @@ class POSIX(Bcfg2.Client.Tools.Tool):
entry.set('qtext', qtxt)
return contentStatus and permissionStatus
- def InstallConfigFile(self, entry):
- """Install ConfigFile entry."""
- self.logger.info("Installing ConfigFile %s" % (entry.get('name')))
+ def Installfile(self, entry):
+ """Install Path type='file' entry."""
+ self.logger.info("Installing file %s" % (entry.get('name')))
parent = "/".join(entry.get('name').split('/')[:-1])
if parent:
@@ -642,9 +546,9 @@ class POSIX(Bcfg2.Client.Tools.Tool):
self.setup.get("paranoid", False) and not \
(entry.get('current_exists', 'true') == 'false'):
bkupnam = entry.get('name').replace('/', '_')
- # current list of backups for this ConfigFile
+ # current list of backups for this file
bkuplist = [f for f in os.listdir(self.ppath) if
- f.startswith(bkupnam)]
+ f.startswith(bkupnam)]
bkuplist.sort()
if len(bkuplist) == int(self.max_copies):
# remove the oldest backup available
@@ -663,7 +567,7 @@ class POSIX(Bcfg2.Client.Tools.Tool):
self.logger.info("Backup of %s saved to %s" %
(entry.get('name'), self.ppath))
except IOError, e:
- self.logger.error("Failed to create backup file for ConfigFile %s" % \
+ self.logger.error("Failed to create backup file for %s" % \
(entry.get('name')))
self.logger.error(e)
return False
@@ -694,7 +598,7 @@ class POSIX(Bcfg2.Client.Tools.Tool):
os.utime(entry.get('name'), (int(entry.get('mtime')),
int(entry.get('mtime'))))
except:
- self.logger.error("ConfigFile %s mtime fix failed" \
+ self.logger.error("File %s mtime fix failed" \
% (entry.get('name')))
return False
return True
@@ -705,42 +609,158 @@ class POSIX(Bcfg2.Client.Tools.Tool):
print(err)
return False
- def Verifydirectory(self, entry, _):
- ret = getattr(self, 'VerifyDirectory')
- return ret(entry, _)
+ def Verifyhardlink(self, entry, _):
+ """Verify HardLink entry."""
+ if entry.get('to') == None:
+ self.logger.error('Entry %s not completely specified. '
+ 'Try running bcfg2-repo-validate.' % \
+ (entry.get('name')))
+ return False
+ try:
+ if os.path.samefile(entry.get('name'), entry.get('to')):
+ return True
+ self.logger.debug("Hardlink %s is incorrect" % \
+ entry.get('name'))
+ entry.set('qtext', "Link %s to %s? [y/N] " % \
+ (entry.get('name'),
+ entry.get('to')))
+ return False
+ except OSError:
+ entry.set('current_exists', 'false')
+ entry.set('qtext', "Link %s to %s? [y/N] " % \
+ (entry.get('name'),
+ entry.get('to')))
+ return False
- def Installdirectory(self, entry):
- ret = getattr(self, 'InstallDirectory')
- return ret(entry)
+ def Installhardlink(self, entry):
+ """Install HardLink entry."""
+ if entry.get('to') == None:
+ self.logger.error('Entry %s not completely specified. '
+ 'Try running bcfg2-repo-validate.' % \
+ (entry.get('name')))
+ return False
+ self.logger.info("Installing Hardlink %s" % (entry.get('name')))
+ if os.path.lexists(entry.get('name')):
+ try:
+ fmode = os.lstat(entry.get('name'))[ST_MODE]
+ if S_ISREG(fmode) or S_ISLNK(fmode):
+ self.logger.debug("Non-directory entry already exists at "
+ "%s. Unlinking entry." % (entry.get('name')))
+ os.unlink(entry.get('name'))
+ elif S_ISDIR(fmode):
+ self.logger.debug("Directory already exists at %s" % \
+ (entry.get('name')))
+ self.cmd.run("mv %s/ %s.bak" % \
+ (entry.get('name'),
+ entry.get('name')))
+ else:
+ os.unlink(entry.get('name'))
+ except OSError:
+ self.logger.info("Hardlink %s cleanup failed" % \
+ (entry.get('name')))
+ try:
+ os.link(entry.get('to'), entry.get('name'))
+ return True
+ except OSError:
+ return False
- def Verifyfile(self, entry, _):
- ret = getattr(self, 'VerifyConfigFile')
- return ret(entry, _)
+ def Verifynonexistent(self, entry, _):
+ """Verify nonexistent entry."""
+ # return true if path does _not_ exist
+ return not os.path.lexists(entry.get('name'))
- def Installfile(self, entry):
- ret = getattr(self, 'InstallConfigFile')
- return ret(entry)
+ def Installnonexistent(self, entry):
+ '''Remove nonexistent entries'''
+ try:
+ os.remove(entry.get('name'))
+ return True
+ except OSError:
+ self.logger.error('Failed to remove %s' % entry.get('name'))
+ return False
def Verifypermissions(self, entry, _):
- ret = getattr(self, 'VerifyPermissions')
- return ret(entry, _)
+ """Verify Path type='permissions' entry"""
+ return self.Verifydirectory(entry, _)
def Installpermissions(self, entry):
- ret = getattr(self, 'InstallPermissions')
- return ret(entry)
+ """Install POSIX permissions"""
+ if entry.get('perms') == None or \
+ entry.get('owner') == None or \
+ entry.get('group') == None:
+ self.logger.error('Entry %s not completely specified. '
+ 'Try running bcfg2-repo-validate.' % (entry.get('name')))
+ return False
+ try:
+ os.chown(entry.get('name'), normUid(entry), normGid(entry))
+ os.chmod(entry.get('name'), calcPerms(S_IFDIR, entry.get('perms')))
+ return True
+ except (OSError, KeyError):
+ self.logger.error('Permission fixup failed for %s' % \
+ (entry.get('name')))
+ return False
def Verifysymlink(self, entry, _):
- ret = getattr(self, 'VerifySymLink')
- return ret(entry, _)
+ """Verify Path type='symlink' entry."""
+ if entry.get('to') == None:
+ self.logger.error('Entry %s not completely specified. '
+ 'Try running bcfg2-repo-validate.' % \
+ (entry.get('name')))
+ return False
+ try:
+ sloc = os.readlink(entry.get('name'))
+ if sloc == entry.get('to'):
+ return True
+ self.logger.debug("Symlink %s points to %s, should be %s" % \
+ (entry.get('name'), sloc, entry.get('to')))
+ entry.set('current_to', sloc)
+ entry.set('qtext', "Link %s to %s? [y/N] " % (entry.get('name'),
+ entry.get('to')))
+ return False
+ except OSError:
+ entry.set('current_exists', 'false')
+ entry.set('qtext', "Link %s to %s? [y/N] " % (entry.get('name'),
+ entry.get('to')))
+ return False
def Installsymlink(self, entry):
- ret = getattr(self, 'InstallSymLink')
- return ret(entry)
+ """Install Path type='symlink' entry."""
+ if entry.get('to') == None:
+ self.logger.error('Entry %s not completely specified. '
+ 'Try running bcfg2-repo-validate.' % \
+ (entry.get('name')))
+ return False
+ self.logger.info("Installing symlink %s" % (entry.get('name')))
+ if os.path.lexists(entry.get('name')):
+ try:
+ fmode = os.lstat(entry.get('name'))[ST_MODE]
+ if S_ISREG(fmode) or S_ISLNK(fmode):
+ self.logger.debug("Non-directory entry already exists at "
+ "%s. Unlinking entry." % \
+ (entry.get('name')))
+ os.unlink(entry.get('name'))
+ elif S_ISDIR(fmode):
+ self.logger.debug("Directory already exists at %s" %\
+ (entry.get('name')))
+ self.cmd.run("mv %s/ %s.bak" % \
+ (entry.get('name'),
+ entry.get('name')))
+ else:
+ os.unlink(entry.get('name'))
+ except OSError:
+ self.logger.info("Symlink %s cleanup failed" %\
+ (entry.get('name')))
+ try:
+ os.symlink(entry.get('to'), entry.get('name'))
+ return True
+ except OSError:
+ return False
def InstallPath(self, entry):
+ """Dispatch install to the proper method according to type"""
ret = getattr(self, 'Install%s' % entry.get('type'))
return ret(entry)
def VerifyPath(self, entry, _):
+ """Dispatch verify to the proper method according to type"""
ret = getattr(self, 'Verify%s' % entry.get('type'))
return ret(entry, _)
diff --git a/src/lib/Client/Tools/YUMng.py b/src/lib/Client/Tools/YUMng.py
index 9fc776471..ce8832395 100644
--- a/src/lib/Client/Tools/YUMng.py
+++ b/src/lib/Client/Tools/YUMng.py
@@ -157,7 +157,7 @@ class YUMng(Bcfg2.Client.Tools.PkgTool):
self.__important__ = self.__important__ + \
[entry.get('name') for struct in config \
for entry in struct \
- if entry.tag in ['Path', 'ConfigFile'] and \
+ if entry.tag in == 'Path' and \
(entry.get('name').startswith('/etc/yum.d') \
or entry.get('name').startswith('/etc/yum.repos.d')) \
or entry.get('name') == '/etc/yum.conf']
diff --git a/src/lib/Client/Tools/__init__.py b/src/lib/Client/Tools/__init__.py
index 1d89e6d02..8a90e130c 100644
--- a/src/lib/Client/Tools/__init__.py
+++ b/src/lib/Client/Tools/__init__.py
@@ -172,8 +172,7 @@ class Tool:
'''Build a list of potentially modified POSIX paths for this entry'''
return [entry.get('name') for struct in self.config.getchildren() \
for entry in struct.getchildren() \
- if entry.tag in ['ConfigFile', 'SymLink', 'Directory',
- 'Permissions', 'Ignore', 'Path']]
+ if entry.tag in ['Ignore', 'Path']]
def gatherCurrentData(self, entry):
"""Default implementation of the information gathering routines."""
diff --git a/src/lib/Server/Admin/Bundle.py b/src/lib/Server/Admin/Bundle.py
index e293c6a4f..41cd5727e 100644
--- a/src/lib/Server/Admin/Bundle.py
+++ b/src/lib/Server/Admin/Bundle.py
@@ -91,7 +91,7 @@ class Bundle(Bcfg2.Server.Admin.MetadataCore):
tree = lxml.etree.parse(bundle_list[int(lineno)])
#Prints bundle content
#print lxml.etree.tostring(tree)
- names = ['Action', 'ConfigFile', 'Directory', 'Package', 'Permission', 'Service', 'SymLink']
+ names = ['Action', 'Package', 'Path', 'Service']
for name in names:
for node in tree.findall("//" + name):
print "%s:\t%s" % (name, node.attrib["name"])
diff --git a/src/lib/Server/Plugins/POSIXCompat.py b/src/lib/Server/Plugins/POSIXCompat.py
deleted file mode 100644
index fc16e4b48..000000000
--- a/src/lib/Server/Plugins/POSIXCompat.py
+++ /dev/null
@@ -1,38 +0,0 @@
-"""This plugin provides a compatibility layer which turns new-style
-POSIX entries into old-style entries.
-"""
-
-__revision__ = '$Revision$'
-
-import Bcfg2.Server.Plugin
-
-COMPAT_DICT = {'file': 'ConfigFile',
- 'directory': 'Directory',
- 'permissions': 'Permissions',
- 'symlink': 'SymLink'}
-
-
-class POSIXCompat(Bcfg2.Server.Plugin.Plugin,
- Bcfg2.Server.Plugin.GoalValidator):
- """POSIXCompat is a goal validator plugin for POSIX entries."""
- name = 'POSIXCompat'
- __version__ = '$Id$'
- __author__ = 'bcfg-dev@mcs.anl.gov'
-
- def __init__(self, core, datastore):
- Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
- Bcfg2.Server.Plugin.GoalValidator.__init__(self)
-
- def validate_goals(self, metadata, goals):
- """Verify that we are generating correct old
- Cfg/Directory/Symlink entries.
- """
- for goal in goals:
- for entry in goal.getchildren():
- if entry.tag == 'Path' and \
- entry.get('type') not in ['nonexistent', 'device']:
- # Use new entry 'type' attribute to map old entry tags
- oldentry = entry
- entry.tag = COMPAT_DICT[entry.get('type')]
- del entry.attrib['type']
- goal.replace(oldentry, entry)
diff --git a/src/lib/Server/Plugins/__init__.py b/src/lib/Server/Plugins/__init__.py
index 758f1219d..c69c37452 100644
--- a/src/lib/Server/Plugins/__init__.py
+++ b/src/lib/Server/Plugins/__init__.py
@@ -22,7 +22,6 @@ __all__ = [
'Properties',
'Probes',
'Pkgmgr',
- 'POSIXCompat',
'Rules',
'SSHbase',
'Snapshots',
diff --git a/src/sbin/bcfg2-repo-validate b/src/sbin/bcfg2-repo-validate
index 1889c9892..3d5efb093 100755
--- a/src/sbin/bcfg2-repo-validate
+++ b/src/sbin/bcfg2-repo-validate
@@ -88,14 +88,14 @@ if __name__ == '__main__':
# (as defined in doc/server/configurationentries)
# TODO: See if it is possible to do this in the schema instead
required_configuration_attrs = {
- 'device':['name', 'owner', 'group', 'dev_type'],
- 'directory':['name', 'owner', 'group', 'perms'],
- 'file':['name', 'owner', 'group', 'perms'],
- 'hardlink':['name', 'to'],
- 'symlink':['name', 'to'],
- 'ignore':['name'],
- 'nonexist':['name'],
- 'permissions':['name', 'owner', 'group', 'perms']}
+ 'device': ['name', 'owner', 'group', 'dev_type'],
+ 'directory': ['name', 'owner', 'group', 'perms'],
+ 'file': ['name', 'owner', 'group', 'perms'],
+ 'hardlink': ['name', 'to'],
+ 'symlink': ['name', 'to'],
+ 'ignore': ['name'],
+ 'nonexist': ['name'],
+ 'permissions': ['name', 'owner', 'group', 'perms']}
for rfile in rules_list:
try:
xdata = lxml.etree.parse(rfile)
@@ -110,6 +110,11 @@ if __name__ == '__main__':
+ ['type'])
except KeyError:
continue
+ if 'dev_type' in required_attrs:
+ dev_type = posixpath.get('dev_type')
+ if dev_type in ['block', 'char']:
+ # check if major/minor are specified
+ required_attrs |= set(['major', 'minor'])
if pathset.issuperset(required_attrs):
continue
else:
@@ -146,16 +151,16 @@ if __name__ == '__main__':
else:
pset.add(ptuple)
- filesets = {'metadata':(metadata_list, "%s/metadata.xsd"),
- 'clients':(clients_list, "%s/clients.xsd"),
- 'info':(info_list, "%s/info.xsd"),
- 'bundle':(bundle_list, "%s/bundle.xsd"),
- 'pkglist':(pkg_list, "%s/pkglist.xsd"),
- 'base':(base_list, "%s/base.xsd"),
- 'rules':(rules_list, "%s/rules.xsd"),
- 'imageinfo':(imageinfo_list, "%s/report-configuration.xsd"),
- 'services':(services_list, "%s/services.xsd"),
- 'deps':(deps_list, "%s/deps.xsd"),
+ filesets = {'metadata': (metadata_list, "%s/metadata.xsd"),
+ 'clients': (clients_list, "%s/clients.xsd"),
+ 'info': (info_list, "%s/info.xsd"),
+ 'bundle': (bundle_list, "%s/bundle.xsd"),
+ 'pkglist': (pkg_list, "%s/pkglist.xsd"),
+ 'base': (base_list, "%s/base.xsd"),
+ 'rules': (rules_list, "%s/rules.xsd"),
+ 'imageinfo': (imageinfo_list, "%s/report-configuration.xsd"),
+ 'services': (services_list, "%s/services.xsd"),
+ 'deps': (deps_list, "%s/deps.xsd"),
'decisions': (dec_list, "%s/decisions.xsd"),
'packages': (pkgcfg_list, "%s/packages.xsd"),
'grouppatterns': (gp_list, "%s/grouppatterns.xsd"),