Page MenuHomeClusterLabs Projects

cts-support.in
No OneTemporary

cts-support.in

#!@PYTHON@
"""Manage support files for Pacemaker CTS."""
# pylint doesn't like the module name "cts-attrd" which is an invalid complaint for this file
# but probably something we want to continue warning about elsewhere
# pylint: disable=invalid-name
# pacemaker imports need to come after we modify sys.path, which pylint will complain about.
# pylint: disable=wrong-import-position
# We access various private members several places in this file, so disable this warning
# file-wide.
# pylint: disable=protected-access
__copyright__ = "Copyright 2024 the Pacemaker project contributors"
__license__ = "GNU General Public License version 2 or later (GPLv2+) WITHOUT ANY WARRANTY"
import argparse
import fcntl
import os
import shutil
import subprocess
import sys
# These imports allow running from a source checkout after running `make`.
# Note that while this doesn't necessarily mean it will successfully run tests,
# but being able to see --help output can be useful.
if os.path.exists("@abs_top_srcdir@/python"):
sys.path.insert(0, "@abs_top_srcdir@/python")
# pylint: disable=comparison-of-constants,comparison-with-itself,condition-evals-to-constant
if os.path.exists("@abs_top_builddir@/python") and "@abs_top_builddir@" != "@abs_top_srcdir@":
sys.path.insert(0, "@abs_top_builddir@/python")
from pacemaker.buildoptions import BuildOptions
from pacemaker.exitstatus import ExitStatus
COROSYNC_RUNTIME_CONF = "cts.conf"
COROSYNC_RUNTIME_UNIT = "corosync.service.d"
DUMMY_DAEMON = "pacemaker-cts-dummyd"
DUMMY_DAEMON_UNIT = "pacemaker-cts-dummyd@.service"
FENCE_DUMMY = "fence_dummy"
FENCE_DUMMY_ALIASES = ["auto_unfence", "no_reboot", "no_on", "no_nodeid"]
LSB_DUMMY = "LSBDummy"
def daemon_reload():
"""Reload the systemd daemon."""
try:
subprocess.call(["systemctl", "daemon-reload"])
except subprocess.SubprocessError:
pass
def install(src, destdir, mode=0o755):
"""Install a file to a given directory with the given mode."""
destfile = "%s/%s" % (destdir, os.path.basename(src))
shutil.copyfile(src, destfile)
os.chmod(destfile, mode)
def makedirs_if_missing(path):
"""If the directory path doesn't exist, create it."""
if os.path.exists(path):
return
os.makedirs(path)
def cmd_install(src):
"""Install support files needed by Pacemaker CTS."""
cmd_uninstall()
if not os.path.exists(src):
sys.exit(ExitStatus.ERROR)
os.chdir(src)
if os.path.exists(BuildOptions.UNIT_DIR):
print("Installing %s ..." % DUMMY_DAEMON)
d = "%s/pacemaker" % BuildOptions.LIBEXEC_DIR
makedirs_if_missing(d)
install(DUMMY_DAEMON, d)
print("Installing %s ..." % DUMMY_DAEMON_UNIT)
install(DUMMY_DAEMON_UNIT, BuildOptions.UNIT_DIR)
daemon_reload()
runtime_unit_dir = "%s/systemd/system" % BuildOptions.RUNTIME_STATE_DIR
if os.path.exists(runtime_unit_dir):
unit_dir = "%s/%s" % (runtime_unit_dir, COROSYNC_RUNTIME_UNIT)
print("Installing %s to %s ..." % (COROSYNC_RUNTIME_CONF, unit_dir))
makedirs_if_missing(unit_dir)
install(COROSYNC_RUNTIME_CONF, unit_dir, 0o644)
daemon_reload()
print("Installing %s to %s ..." % (FENCE_DUMMY, BuildOptions._FENCE_BINDIR))
makedirs_if_missing(BuildOptions._FENCE_BINDIR)
install(FENCE_DUMMY, BuildOptions._FENCE_BINDIR)
for alias in FENCE_DUMMY_ALIASES:
print("Installing fence_dummy_%s to %s ..." % (alias, BuildOptions._FENCE_BINDIR))
try:
os.symlink(FENCE_DUMMY, "%s/fence_dummy_%s" % (BuildOptions._FENCE_BINDIR, alias))
except OSError:
sys.exit(ExitStatus.ERROR)
if BuildOptions.INIT_DIR is not None:
print("Installing %s to %s ..." % (LSB_DUMMY, BuildOptions.INIT_DIR))
makedirs_if_missing(BuildOptions.INIT_DIR)
install(LSB_DUMMY, BuildOptions.INIT_DIR)
def cmd_uninstall():
"""Remove support files needed by Pacemaker CTS."""
dummy_unit_file = "%s/%s" % (BuildOptions.UNIT_DIR, DUMMY_DAEMON_UNIT)
if os.path.exists(dummy_unit_file):
print("Removing %s ..." % dummy_unit_file)
os.remove(dummy_unit_file)
daemon_reload()
corosync_runtime_dir = "%s/systemd/system/%s" % (BuildOptions.RUNTIME_STATE_DIR, COROSYNC_RUNTIME_UNIT)
if os.path.exists(corosync_runtime_dir):
print("Removing %s ..." % corosync_runtime_dir)
shutil.rmtree(corosync_runtime_dir)
daemon_reload()
for f in ["%s/pacemaker/%s" % (BuildOptions.LIBEXEC_DIR, DUMMY_DAEMON),
"%s/%s" % (BuildOptions._FENCE_BINDIR, FENCE_DUMMY),
"%s/%s" % (BuildOptions.INIT_DIR, LSB_DUMMY)]:
if not os.path.exists(f):
continue
print("Removing %s ..." % f)
os.remove(f)
for alias in FENCE_DUMMY_ALIASES:
f = "%s/fence_dummy_%s" % (BuildOptions._FENCE_BINDIR, alias)
if not os.path.exists(f) and not os.path.islink(f):
continue
print("Removing %s ..." % f)
os.remove(f)
def cmd_watch(filename, limit, offset, prefix):
"""Watch a log file."""
if not os.access(filename, os.R_OK):
print("%sLast read: %d, limit=%d, count=%d - unreadable" % (prefix, 0, limit, 0))
sys.exit(ExitStatus.ERROR)
with open(filename, "r", encoding="utf-8") as logfile:
logfile.seek(0, os.SEEK_END)
newsize = logfile.tell()
if offset != 'EOF':
offset = int(offset)
if newsize >= offset:
logfile.seek(offset)
else:
print("%sFile truncated from %d to %d" % (prefix, offset, newsize))
if (newsize * 1.05) < offset:
logfile.seek(0)
# Don't block when we reach EOF
fcntl.fcntl(logfile.fileno(), fcntl.F_SETFL, os.O_NONBLOCK)
count = 0
while True:
if logfile.tell() >= newsize:
break
if limit and count >= limit:
break
line = logfile.readline()
if not line:
break
print(line.strip())
count += 1
print("%sLast read: %d, limit=%d, count=%d" % (prefix, logfile.tell(), limit, count))
def build_options():
"""Handle command line arguments."""
# Create the top-level parser
parser = argparse.ArgumentParser(description="Support tool for CTS")
subparsers = parser.add_subparsers(dest="subparser_name")
# Create the parser for the "install" command
subparsers.add_parser("install", help="Install support files")
# Create the parser for the "uninstall" command
subparsers.add_parser("uninstall", help="Remove support files")
# Create the parser for the "watch" command
watch_parser = subparsers.add_parser("watch", help="Remote log watcher")
watch_parser.add_argument("-f", "--filename", default="/var/log/messages",
help="File to watch")
watch_parser.add_argument("-l", "--limit", type=int, default=0,
help="Maximum number of lines to read")
watch_parser.add_argument("-o", "--offset", default=0,
help="Which line number to start reading from")
watch_parser.add_argument("-p", "--prefix", default="",
help="String to add to the beginning of each line")
args = parser.parse_args()
return args
if __name__ == "__main__":
opts = build_options()
if os.geteuid() != 0:
print("This command must be run as root")
sys.exit(ExitStatus.ERROR)
# If the install directory doesn't exist, assume we're in a build directory.
data_dir = "%s/pacemaker/tests/cts" % BuildOptions.DATA_DIR
if not os.path.exists(data_dir):
data_dir = "%s/pacemaker/tests/cts" % BuildOptions._BUILD_DIR
if opts.subparser_name == "install":
cmd_install(data_dir)
if opts.subparser_name == "uninstall":
cmd_uninstall()
if opts.subparser_name == "watch":
cmd_watch(opts.filename, opts.limit, opts.offset, opts.prefix)
# vim: set filetype=python expandtab tabstop=4 softtabstop=4 shiftwidth=4 textwidth=120:

File Metadata

Mime Type
text/x-script.python
Expires
Thu, Jul 10, 1:59 AM (1 d, 9 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2009629
Default Alt Text
cts-support.in (8 KB)

Event Timeline