summaryrefslogtreecommitdiffstats
path: root/src/lib/Bcfg2/Client
diff options
context:
space:
mode:
authorChris St. Pierre <chris.a.st.pierre@gmail.com>2013-06-27 08:19:09 -0400
committerChris St. Pierre <chris.a.st.pierre@gmail.com>2013-06-27 08:19:09 -0400
commit317d3087459538877100032733477362f456f550 (patch)
tree27fabdff3649c75bcdd9de8ccde5c5826c679e5e /src/lib/Bcfg2/Client
parent9d5e8170292e17d3b087878918562dcf502f70d4 (diff)
parenta519dc9298317b678bca43597892df5aa13d874d (diff)
downloadbcfg2-317d3087459538877100032733477362f456f550.tar.gz
bcfg2-317d3087459538877100032733477362f456f550.tar.bz2
bcfg2-317d3087459538877100032733477362f456f550.zip
Merge branch 'maint'
Conflicts: doc/server/plugins/generators/cfg.txt doc/server/plugins/generators/tcheetah.txt src/lib/Bcfg2/Server/Admin/Xcmd.py src/lib/Bcfg2/Server/Plugins/Cfg/__init__.py src/lib/Bcfg2/Server/Plugins/Packages/Yum.py
Diffstat (limited to 'src/lib/Bcfg2/Client')
-rw-r--r--src/lib/Bcfg2/Client/Frame.py4
-rw-r--r--src/lib/Bcfg2/Client/Tools/Action.py16
-rw-r--r--src/lib/Bcfg2/Client/Tools/Chkconfig.py30
-rw-r--r--src/lib/Bcfg2/Client/Tools/DebInit.py36
-rw-r--r--src/lib/Bcfg2/Client/Tools/POSIX/File.py6
-rw-r--r--src/lib/Bcfg2/Client/Tools/RcUpdate.py30
-rw-r--r--src/lib/Bcfg2/Client/Tools/VCS.py119
-rw-r--r--src/lib/Bcfg2/Client/__init__.py7
8 files changed, 163 insertions, 85 deletions
diff --git a/src/lib/Bcfg2/Client/Frame.py b/src/lib/Bcfg2/Client/Frame.py
index b24b46dbc..a668a0870 100644
--- a/src/lib/Bcfg2/Client/Frame.py
+++ b/src/lib/Bcfg2/Client/Frame.py
@@ -111,8 +111,8 @@ class Frame(object):
self.logger.warning(deprecated)
experimental = [tool.name for tool in self.tools if tool.experimental]
if experimental:
- self.logger.warning("Loaded experimental tool drivers:")
- self.logger.warning(experimental)
+ self.logger.info("Loaded experimental tool drivers:")
+ self.logger.info(experimental)
# find entries not handled by any tools
self.unhandled = [entry for struct in config
diff --git a/src/lib/Bcfg2/Client/Tools/Action.py b/src/lib/Bcfg2/Client/Tools/Action.py
index fd2c467d7..05e35befc 100644
--- a/src/lib/Bcfg2/Client/Tools/Action.py
+++ b/src/lib/Bcfg2/Client/Tools/Action.py
@@ -31,10 +31,17 @@ class Action(Bcfg2.Client.Tools.Tool):
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:
@@ -47,8 +54,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 0f5f32302..156f76159 100644
--- a/src/lib/Bcfg2/Client/Tools/Chkconfig.py
+++ b/src/lib/Bcfg2/Client/Tools/Chkconfig.py
@@ -57,27 +57,29 @@ class Chkconfig(Bcfg2.Client.Tools.SvcTool):
return True
current_bootstatus = self.verify_bootstatus(entry, bootstatus)
- svcstatus = self.check_service(entry)
- if entry.get('status') == 'on':
- if svcstatus:
- current_srvstatus = True
- else:
- current_srvstatus = False
- elif entry.get('status') == 'off':
- if svcstatus:
- current_srvstatus = False
- else:
- current_srvstatus = True
- else:
+ if entry.get('status') == 'ignore':
# 'ignore' should verify
- current_srvstatus = True
+ 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_srvstatus
+ return current_bootstatus and current_svcstatus
def InstallService(self, entry):
"""Install Service entry."""
diff --git a/src/lib/Bcfg2/Client/Tools/DebInit.py b/src/lib/Bcfg2/Client/Tools/DebInit.py
index 116d4f8b0..761c51db7 100644
--- a/src/lib/Bcfg2/Client/Tools/DebInit.py
+++ b/src/lib/Bcfg2/Client/Tools/DebInit.py
@@ -18,6 +18,9 @@ class DebInit(Bcfg2.Client.Tools.SvcTool):
svcre = \
re.compile(r'/etc/.*/(?P<action>[SK])(?P<sequence>\d+)(?P<name>\S+)')
+ 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')))
@@ -78,27 +81,29 @@ class DebInit(Bcfg2.Client.Tools.SvcTool):
return True
current_bootstatus = self.verify_bootstatus(entry, bootstatus)
- svcstatus = self.check_service(entry)
- if entry.get('status') == 'on':
- if svcstatus:
- current_srvstatus = True
- else:
- current_srvstatus = False
- elif entry.get('status') == 'off':
- if svcstatus:
- current_srvstatus = False
- else:
- current_srvstatus = True
- else:
+ if entry.get('status') == 'ignore':
# 'ignore' should verify
- current_srvstatus = True
+ 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_srvstatus
+ return current_bootstatus and current_svcstatus
def InstallService(self, entry):
"""Install Service entry."""
@@ -165,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/POSIX/File.py b/src/lib/Bcfg2/Client/Tools/POSIX/File.py
index 168c35c98..9f47fb53a 100644
--- a/src/lib/Bcfg2/Client/Tools/POSIX/File.py
+++ b/src/lib/Bcfg2/Client/Tools/POSIX/File.py
@@ -146,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
@@ -163,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/RcUpdate.py b/src/lib/Bcfg2/Client/Tools/RcUpdate.py
index d6329256e..8e9626521 100644
--- a/src/lib/Bcfg2/Client/Tools/RcUpdate.py
+++ b/src/lib/Bcfg2/Client/Tools/RcUpdate.py
@@ -62,27 +62,29 @@ class RcUpdate(Bcfg2.Client.Tools.SvcTool):
entry.get('name'))
return False
- svcstatus = self.check_service(entry)
- if entry.get('status') == 'on':
- if svcstatus:
- current_srvstatus = True
- else:
- current_srvstatus = False
- elif entry.get('status') == 'off':
- if svcstatus:
- current_srvstatus = False
- else:
- current_srvstatus = True
- else:
+ if entry.get('status') == 'ignore':
# 'ignore' should verify
- current_srvstatus = True
+ 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_srvstatus
+ return current_bootstatus and current_svcstatus
def InstallService(self, entry):
"""Install Service entry."""
diff --git a/src/lib/Bcfg2/Client/Tools/VCS.py b/src/lib/Bcfg2/Client/Tools/VCS.py
index 1ab867215..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,45 +117,64 @@ 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"""
+ headrev = pysvn.Revision( pysvn.opt_revision_kind.head )
client = pysvn.Client()
try:
cur_rev = str(client.info(entry.get('name')).revision.number)
+ server = client.info2(entry.get('sourceurl'), headrev, recurse=False)
+ if server:
+ server_rev = str(server[0][1].rev.number)
except:
self.logger.info("Repository %s does not exist" % entry.get('name'))
return False
+ if entry.get('revision') == 'latest' and cur_rev == server_rev:
+ return True
+
if cur_rev != entry.get('revision'):
self.logger.info("At revision %s need to go to revision %s" %
(cur_rev, entry.get('revision')))
diff --git a/src/lib/Bcfg2/Client/__init__.py b/src/lib/Bcfg2/Client/__init__.py
index 3bc261f2f..25603186e 100644
--- a/src/lib/Bcfg2/Client/__init__.py
+++ b/src/lib/Bcfg2/Client/__init__.py
@@ -22,8 +22,5 @@ def prompt(msg):
ans = input(msg)
return ans in ['y', 'Y']
except EOFError:
- # python 2.4.3 on CentOS doesn't like ^C for some reason
- return False
- except:
- print("Error while reading input: %s" % sys.exc_info()[1])
- return False
+ # handle ^C on rhel-based platforms
+ raise SystemExit(1)