summaryrefslogtreecommitdiffstats
path: root/base/all/root/scripts/cluster_configure/cluster-configure.py
diff options
context:
space:
mode:
Diffstat (limited to 'base/all/root/scripts/cluster_configure/cluster-configure.py')
-rwxr-xr-xbase/all/root/scripts/cluster_configure/cluster-configure.py452
1 files changed, 0 insertions, 452 deletions
diff --git a/base/all/root/scripts/cluster_configure/cluster-configure.py b/base/all/root/scripts/cluster_configure/cluster-configure.py
deleted file mode 100755
index e94579e..0000000
--- a/base/all/root/scripts/cluster_configure/cluster-configure.py
+++ /dev/null
@@ -1,452 +0,0 @@
-#!/usr/bin/env python
-
-# Configure clustered Samba nodes
-
-# Copyright (C) Martin Schwenke 2010
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
-# (at your option) any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, see <http://www.gnu.org/licenses/>.
-
-import os
-import sys
-import optparse # Newer argparse not yet in RHEL5/EPEL.
-import ConfigParser
-import logging
-import re
-import subprocess
-import errno
-import filecmp
-import shutil
-import glob
-import string
-
-lib_dir = "lib"
-sys.path.append(lib_dir)
-
-import logging
-
-def process_args():
- usage = "usage: %prog [options] configfile"
-
- parser = optparse.OptionParser(usage=usage)
-
- parser.add_option("-t", "--templates",
- action="store", dest="templates",
- default="templates/rhel",
- help="directory containing templates")
- parser.add_option("-f", "--force",
- action="store_true", dest="force",
- default=False,
- help="install configuration files even if unchanged",)
- parser.add_option("-r", "--no-reload",
- action="store_true", dest="no_reload",
- default=False,
- help="""don't run the "reload" script for
-services - this is usually done to make services reload their configuration
-after any changes""")
- parser.add_option("-n", "--simulate",
- action="store_true", dest="simulate",
- default=False,
- help="""don't actually install configuration
-files - this will leave the configuration files in the temporary staging
-area - implies -r""")
- parser.add_option("-s", "--staging",
- action="store", dest="staging",
- default="staging",
- help="directory to stage the files to be installed")
- parser.add_option("-v", "--verbose",
- action="count", dest="verbose",
- default=0,
- help="print information and actions taken to stdout")
- parser.add_option("-l", "--log-file",
- action="store", dest="log_file", default=None,
- metavar="FILE",
- help="append information and actions taken to FILE")
- (options, args) = parser.parse_args()
-
- if len(args) != 1:
- parser.error("configuration file must be specified")
-
- options.config = args[0]
-
- return options
-
-def setup_logging():
-
- global options
-
- logger = logging.getLogger("cluster-configure")
- logger.setLevel(logging.ERROR)
-
- sh = logging.StreamHandler(sys.stderr)
- sh.handleError = lambda x : (logging.shutdown(), sys.exit())
- logger.addHandler(sh)
-
- if options.verbose == 1:
- logger.setLevel(logging.WARNING)
- elif options.verbose == 2:
- logger.setLevel(logging.INFO)
- elif options.verbose >= 3:
- logger.setLevel(logging.DEBUG)
-
- if options.log_file is not None:
- fh = logging.FileHandler(options.log_file)
- # The formatting option %(funcName)s would be useful here but
- # it only appeared in Python 2.5 and this script will be run
- # on Python 2.4.
- formatter = logging.Formatter(
- "%(asctime)s - %(name)s - %(levelname)s - %(message)s")
- fh.setFormatter(formatter)
- logger.addHandler(fh)
-
- return logger
-
-def _rpm_parse_version(v):
- ret = []
- for x in re.split("[^A-Za-z0-9]", v):
- try:
- ret.append(int(x))
- except ValueError:
- ret.append(x)
- return ret
-
-config = None
-options = None
-logger = None
-
-class Package(object):
- def __init__(self, config, directory):
- self.config = config
- self.directory = directory
- self.version = None
- self.platform = None
- self.version_dir = None
- self.files = list()
- self.files_to_install = list()
-
- m = re.match("\d\d\.(.*)", directory)
- if m is None:
- raise RuntimeError, \
- ("invalid template package directory %s" % directory)
- self.name = m.group(1)
- self.stage = os.path.join(options.staging, self.name)
-
- def _get_version(self):
- if os.path.exists("/etc/redhat-release"):
- p = subprocess.Popen(["rpm", "-q", self.name],
- stdout=subprocess.PIPE)
- out = p.communicate()[0]
- status = p.wait()
- if status == 0:
- out.replace(self.name + "-", "")
- self.version = string.strip(out)
- self.platform = "rpm"
- logger.debug("_get_version: package %s has version %s",
- self.name, self.version)
- return True
- elif os.path.exists("/etc/debian_version"):
- p = subprocess.Popen(["dpkg-query", "-W", "-f", "${Version}",
- self.name],
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
- out = p.communicate()[0]
- status = p.wait()
- if status == 0 and len(out) > 0:
- self.version = string.strip(out)
- self.platform = "deb"
- logger.debug("_get_version: package %s has version %s",
- self.name, self.version)
- return True
-
- logger.info("_get_version: package %s is not installed", self.name)
- return False
-
- # Currently Red Hat specific...
- def _check_version(self, min=None, max=None):
- v = _rpm_parse_version(self.version)
- return min is None or \
- (_rpm_parse_version(min) <= v and \
- (max is None or v < _rpm_parse_version(max)))
-
- def find_version_dir(self):
- if self._get_version():
- pdir = os.path.join(options.templates, self.directory)
- versions = sorted(os.listdir(pdir))
- # FIXME: filter out any without #, since they're meaningless.
- versions.reverse() # bare "#" comes last since it is the default
-
- for i in versions:
- try:
- (min, max) = map(lambda x: len(x) and x or None, i.split("#"))
- except ValueError:
- logger.warn("_find_version_dir: skipping invalid version subdirectory %s" % i)
- continue
-
- if self._check_version(min, max):
- self.version_dir = os.path.join(pdir, i)
- logger.info("_find_version_dir: found version directory %s" % self.version_dir)
- return True
- return False
-
- def _find_template_files(self, fdir):
- """Find the available templates in the given file directory fdir."""
- for (root, dirs, files) in os.walk(fdir):
- for f in files:
- # os.path.relpath is not available in older Python
- frel = os.path.join(root, f).replace(fdir + "/", "", 1)
- logger.debug("_find_template_files: add template file %s" % frel)
- self.files.append(frel)
-
- def _substitute_template(self, contents):
- """Expand the given template fdir/file into the staging area."""
-
- logger.debug("_expand_template: subsitute variables into %s", file)
-
- # Find variables in template and substitute values.
- variables = sorted(set(re.findall("!!((\w+)((=)([^!]*))?)!!",
- contents)))
- # r is the default replacement value for v.
- for (a, v, x, e, r) in variables:
- try:
- r = self.config.get("package:" + self.name, v)
- except (ConfigParser.NoSectionError, ConfigParser.NoOptionError), s:
- # This is the equals sign. if it is there then we have default.
- if e == "":
- raise
-
- contents = contents.replace("!!%s!!" % a, r)
-
- # Find plugin expressions in template and subsitute values.
- exprs = re.findall("!!%([^!]+)!!", contents)
- for e in exprs:
- (m, f, rest) = re.split("[:(]", e, 2)
- foo = 'plugins["%s"].%s(config, "%s", %s' % (m, f, self.name, rest)
- r = eval(foo)
- if r is None:
- return None
- contents = contents.replace("!!%%%s!!" % e, r)
-
- # Find general python expressions in template and subsitute values.
- exprs = re.findall("!!\|([^!]+)!!", contents)
- for e in exprs:
- r = eval(e)
- if r is None:
- return None
- contents = contents.replace("!!|%s!!" % e, r)
-
- return contents
-
- def _expand_template(self, fdir, file):
- """Expand the given template fdir/file into the staging area."""
-
- logger.debug("_expand_template: subsitute variables into %s", file)
-
- # Read input file.
- src = os.path.join(fdir, file)
- f = open(src)
- contents = f.read()
- f.close()
-
- contents = self._substitute_template(contents)
-
- # Ensure output directory exists in staging area.
- dst = os.path.join(self.stage, file)
- try:
- os.makedirs(os.path.dirname(dst))
- except OSError, exc:
- if exc.errno == errno.EEXIST:
- pass
- else: raise
-
- # Write output file into staging area, unless it is None,
- # which means to remove the file if it exists.
- if contents is not None:
- f = open(dst, "w")
- f.write(contents)
- f.close()
- else:
- try:
- os.remove(dst)
- except OSError, exc:
- if exc.errno == errno.ENOENT:
- pass
- else: raise
-
- def _would_install_file(self, file):
- """Check if a file should be installed from the staging area
- because it is different to the currently installed file (or if
- there is no installed file)."""
-
- src = os.path.join(self.stage, file)
- dst = os.path.join("/", file)
-
- if not os.path.exists(src) and not os.path.exists(dst):
- logger.debug("_would_install_file: skip install of %s (missing)", dst)
- return False
-
- try:
- if not options.force and filecmp.cmp(src, dst, shallow=False):
- logger.debug("_would_install_file: skip install of %s (unchanged)", dst)
- return False
- except OSError, exc:
- if exc.errno == errno.ENOENT:
- pass
- else: raise
-
- logger.info("_would_install_file: would install file %s", dst)
- return True
-
- def would_install_files(self):
- """For the templates in our packages files area, expand each
- template into the staging area and check if it would be
- installed due to a change. Return True if any files would be
- installed, False otherwise."""
-
- fdir = os.path.join(self.version_dir, "files")
-
- shutil.rmtree(self.stage, ignore_errors=True)
-
- self._find_template_files(fdir)
- for f in self.files:
- self._expand_template(fdir, f)
-
- for f in self.files:
- if self._would_install_file(f):
- self.files_to_install.append(f)
-
- return self.files_to_install
-
- def _install_file(self, file):
- """Install file from the staging area ."""
-
- src = os.path.join(self.stage, file)
- dst = os.path.join("/", file)
-
- if os.path.exists(src):
- logger.info("_install_file: install file %s", dst)
- shutil.copy2(src, dst)
- else:
- logger.info("_install_file: remove file %s", dst)
- try:
- os.remove(dst)
- except OSError, exc:
- if exc.errno == errno.ENOENT:
- pass
- else: raise
-
- def install_files(self):
- """Install the list of files from self.files_to_install."""
-
- for f in self.files_to_install:
- self._install_file(f)
-
- def run_event(self, event):
- """Run the given event script for the service, if present."""
- es = os.path.join(self.version_dir, "events", event)
- if os.path.exists(es) and os.access(es, os.X_OK):
- p = subprocess.Popen([es],
- stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT)
- out = p.communicate()[0]
- status = p.wait()
- if status == 0:
- logger.info("_run_event: successfully ran event script %s", es)
- else:
- logger.error("""_run_event: error running event script "%s":
-"%s" """,
- es , string.strip(out))
- else:
- logger.debug("_run_event: no event script %s in %s", event,
- self.version_dir)
-
-
-plugins = {}
-
-def load_plugins():
- global plugins
-
- plugin_dir = "plugins"
-
- sys.path.append(plugin_dir)
- for f in map(lambda x: os.path.splitext(os.path.basename(x))[0],
- glob.glob(os.path.join(plugin_dir, "*.py"))):
-
- plugins[f] = __import__(f)
-
-def ctdb_socket():
-
- ret = os.getenv('CTDB_SOCKET')
-
- if ret is None:
- ctdb = '/usr/bin/ctdb'
- if os.path.exists(ctdb):
- cmd = "strings " + ctdb + " | grep -E '/ctdbd?\.socket$'"
- p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
- out = p.communicate()[0]
- status = p.wait()
- if status == 0:
- ret = string.rstrip(out)
- else:
- logger.warning('Failed to find socket path in "' + ctdb +
- '" - falling back to default')
- else:
- logger.warning('Failed to find "' + ctdb +
- '" - falling back to default')
- if ret is None:
- ret = '/var/run/ctdb/ctdbd.socket'
-
- return ret
-
-def main():
- global config, options, logger
-
- options = process_args()
-
- logger = setup_logging()
-
- load_plugins()
-
- os.environ["PATH"] = os.getcwd() + ":" + os.environ["PATH"]
-
- logger.debug("main: read configuration from %s", options.config)
- config = ConfigParser.SafeConfigParser()
- config.readfp(open(options.config))
-
- # Run the check function in every plugin that defines it.
- config_status = True
- for p in plugins.iterkeys():
- func = getattr(plugins[p], "check", None)
- if callable(func):
- if not func(config):
- config_status = False
- if not config_status:
- logger.error("main: exiting due to previous configuration errors")
- return 1
-
- # Process templates.
- for d in sorted(os.listdir(options.templates)):
- try:
- p = Package(config, d)
- if p.find_version_dir():
- if p.would_install_files() and not options.simulate:
- p.run_event("pre")
- p.install_files()
- p.run_event("post")
- except RuntimeError, s:
- logger.info("main: ignoring %s", s)
-
- logging.shutdown()
-
-
-if __name__ == '__main__':
- sys.exit(main())