On 08/05/18 at 09:14pm, Kenneth Dsouza wrote:
From: Kenneth D'souza <kdsouza(a)redhat.com>
A cmdline tool to edit and retrieve information from /etc/kdump.conf.
This tool will avoid typos and have basic sanity check for options.
It would be good to be able to handle /etc/sysconfig/kdump as well as
kdump.conf.
BTW, a manpage is needed.
Anyway, thanks for the patch.
>
> Signed-off-by: Kenneth D'souza <kdsouza(a)redhat.com>
> ---
> kdump-config.py | 281 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 281 insertions(+)
> create mode 100755 kdump-config.py
>
> diff --git a/kdump-config.py b/kdump-config.py
> new file mode 100755
> index 0000000..07b3201
> --- /dev/null
> +++ b/kdump-config.py
> @@ -0,0 +1,281 @@
> +#!/usr/bin/python
> +# kdump-config.py - cmdline tool to display and manipulate configuration information
of /etc/kdump.conf
> +# Author: Kenneth D'souza <kdsouza(a)redhat.com>
> +#
> +# 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 2 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, write to the Free Software
> +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> +
> +import sys
> +import os
> +import stat
> +import argparse
> +import subprocess
> +
> +CONFIG_FILE = "/etc/kdump.conf"
> +
> +
> +# Filter comments and optional settings.
> +def filter_data(data):
> + comments = []
> + data_without_comments = []
> + for line in data:
> + line = line.strip()
> + if line.startswith('#'):
> + comments.append(line)
> + else:
> + data_without_comments.append(line)
> + return comments, data_without_comments
> +
> +
> +# Get only unique data, avoids duplicate.
> +def unique(data_without_comments, option):
> + unique_data = set()
> + for line in data_without_comments:
> + if len(line.split()) > 1:
> + if line.startswith(
> + ("path", "core_collector", "raw",
"nfs", "ssh", "kdump_post",
> + "kdump_pre", "extra_bins",
"extra_modules", "sshkey",
> + "default", "debug_mem_level",
"force_rebuild",
> + "force_no_rebuild", "dracut_args",
"fence_kdump_args",
> + "fence_kdump_nodes", "ext2", "ext3",
"ext4", "btfs", "minix",
> + "xfs")):
> + if line not in unique_data and not line.startswith(option + '
'):
> + if option == "ssh":
> + if not line.startswith(
> + ("nfs", "raw", "ext4",
"ext3", "ext2",
> + "xfs", "btrfs",
"minix")):
> + unique_data.add(line)
> + elif option == "nfs":
> + if not line.startswith(
> + ("ssh", "raw", "ext4",
"ext3", "ext2", "xfs",
> + "btrfs", "minix")):
> + unique_data.add(line)
> + elif option == "raw":
> + if not line.startswith(
> + ("nfs", "ssh", "ext4",
"ext3", "ext2", "xfs",
> + "btrfs", "minix")):
> + unique_data.add(line)
> + elif option in ("ext2", "ext3",
"ext4", "xfs", "btrfs",
> + "minix"):
> + if not line.startswith(("ssh", "nfs",
"raw")):
> + unique_data.add(line)
> + else:
> + unique_data.add(line)
> + return unique_data
> +
> +
> +# We cannot have both the options set to be 1.
> +def check_for_mutual_exculsive(unique_data):
> + for line in unique_data:
> + if line.startswith("force_no_rebuild") or line.startswith(
> + "force_rebuild"):
> + optional = line.split()[1]
> + if optional == value == "1":
> + print("force_no_rebuild and force_rebuild cannot be 1 at the
same time.")
> + return True
> + return False
> +
> +
> +# Check if ssh server is set, if not give warning.
> +def checks_for_ssh(unique_data):
> + for line in unique_data:
> + if line.find("ssh") != -1:
> + return True
> + return False
> +
> +
> +# Write changes to the file with comments, unique data and optional
> +# settings given by the user.
> +def replace_value_write(comments, unique_data, option, value, unset_value):
> + try:
> + with open(CONFIG_FILE, "r+") as f:
> + f.seek(0)
> + f.truncate()
> + for item in comments:
> + f.write("%s\n" % item)
> + for i in range(len(unique_data)):
> + f.write("%s\n" % unique_data[i])
> + if not unset_value:
> + append_txt = ("%s %s\n" % (option, value))
> + f.write("%s" % append_txt)
> + f.close()
> + except IOError as reason:
> + print("You need to have root privileges to run this option.")
> + print("%s" % reason)
> +
> +
> +# Read the file only once and save the data.
> +def check(CONFIG_FILE, option, value, unset_value):
> + with open(CONFIG_FILE, "r") as f1:
> + data = f1.readlines()
> + comments, data_without_comments = filter_data(data)
> + unique_data = list(unique(data_without_comments, option))
> + unique_data = list(filter(None, unique_data))
> + if option == "force_no_rebuild" or option ==
"force_rebuild" and value == "1":
> + result = check_for_mutual_exculsive(unique_data)
> + if result:
> + sys.exit(1)
> + if option == "sshkey":
> + result_ssh = checks_for_ssh(unique_data)
> + if not result_ssh:
> + print("Warning: Remember to add an entry for ssh")
> + replace_value_write(comments, unique_data, option, value, unset_value)
> + f1.close()
> +
> +
> +# Check if the device is valid, check the option passed and work accordingly:
> +def check_device(option, value):
> + try:
> + if not stat.S_ISBLK(os.lstat(value).st_mode):
> + print("not a valid device '%s'" % value)
> + elif option == "raw":
> + check(CONFIG_FILE, option, args.raw, False)
> + else:
> + cmd = subprocess.Popen(
> + "lsblk --nodeps -p -n -o FSTYPE,UUID %s " % (value),
> + stdout=subprocess.PIPE,
> + stderr=subprocess.STDOUT,
> + shell=True)
> + option = cmd.communicate()[0].strip().decode()
> + fstype, UUID = option.split()
> + if fstype in ("ext2", "ext3", "ext4",
"xfs", "btrfs", "minix"):
> + check(CONFIG_FILE, fstype, "UUID=" + UUID, False)
> + else:
> + print("Filesystem '%s' not supported." % fstype)
> + except ValueError:
> + print("'%s' does not contain a valid Filesystem." %
value)
> + except Exception:
> + print("not a valid device '%s'" % value)
> +
> +
> +# Check if dump target is mounted:
> +def check_mnt(nfs_mount):
> + cmd = subprocess.Popen(
> + "findmnt -t nfs,nfs4 %s -o SOURCE -n " % (nfs_mount),
> + stdout=subprocess.PIPE,
> + stderr=subprocess.STDOUT,
> + shell=True)
> + option = cmd.communicate()[0].strip().decode()
> + if not option.strip():
> + print("Error: Dump target '%s' is probably not mounted or
valid" %
> + nfs_mount)
> + else:
> + check(CONFIG_FILE, "nfs", option, False)
> +
> +
> +# Display configuration settings from /etc/kdump.conf:
> +def display_show_config(data_without_comments):
> + for item in data_without_comments:
> + print(item)
> +
> +
> +# Check if kdump config file exists.
> +try:
> + lines = open(CONFIG_FILE).readlines()
> +except IOError as reason:
> + print("Error reading kdump configuration.")
> + exit("%s" % reason)
> +
> +# Check if no arguments are given.
> +if len(sys.argv) < 2:
> + exit("Please specify an action to perform. \nTry `kdump-config --help'
for more information.")
> +
> +parser = argparse.ArgumentParser(
> + description="Please specify an action to perform,")
> +parser.add_argument(
> + "--path",
> + help="path represents the file system path in which vmcore will be
saved.")
> +parser.add_argument("--raw", help=" specify raw device ex:
/dev/sdc1")
> +parser.add_argument(
> + "--nfs", help="specify nfs-server ex:
my.server.com:/export/tmp")
> +parser.add_argument("--ssh", help="specify ssh server ex:
user(a)my.server.com")
> +parser.add_argument(
> + "--sshkey", help="specify the path of the ssh key to use when
dumping.")
> +parser.add_argument(
> + "--showconfig", action="store_true", help="show
configuration settings.")
> +parser.add_argument(
> + "--local_fs", help="specify local device ex:
/dev/myvg/mylv")
> +parser.add_argument("--unset", help="unset a given option ex:
path")
> +parser.add_argument(
> + "--force_no_rebuild",
> + choices=["1", "0"],
> + help="specify 1 to bypass rebuilding of kdump initrd.")
> +parser.add_argument(
> + "--force_rebuild",
> + choices=["1", "0"],
> + help="specify 1 to force rebuilding kdump initrd every time when kdump
service starts.")
> +parser.add_argument(
> + "--default",
> + choices=["reboot", "halt", "poweroff",
"shell", "dump_to_rootfs"],
> + help="Action to perform in case dumping to the intended target
fails.")
> +
> +args = parser.parse_args()
> +
> +if args.default:
> + option = "default"
> + value = args.default
> + check(CONFIG_FILE, option, value, False)
> +
> +if args.path:
> + option = "path"
> + value = args.path
> + check(CONFIG_FILE, option, value, False)
> +
> +if args.showconfig:
> + with open(CONFIG_FILE, "r") as f2:
> + data = f2.readlines()
> + comments, data_without_comments = filter_data(data)
> + display_show_config(data_without_comments)
> +
> +if args.raw:
> + option = "raw"
> + device = os.path.realpath(args.raw)
> + check_device(option, device)
> +
> +if args.force_rebuild:
> + option = "force_rebuild"
> + value = args.force_rebuild
> + check(CONFIG_FILE, option, value, False)
> +
> +if args.force_no_rebuild:
> + option = "force_no_rebuild"
> + value = args.force_no_rebuild
> + check(CONFIG_FILE, option, value, False)
> +
> +if args.nfs:
> + option = "nfs"
> + value = args.nfs
> + check_mnt(value)
> +
> +if args.ssh:
> + option = "ssh"
> + value = args.ssh
> + check(CONFIG_FILE, option, value, False)
> +
> +if args.sshkey:
> + if not os.path.isfile(args.sshkey):
> + exit("Invalid file '%s'" % args.sshkey)
> + option = "sshkey"
> + value = args.sshkey
> + check(CONFIG_FILE, option, value, False)
> +
> +if args.local_fs:
> + device = os.path.realpath(args.local_fs)
> + option = "local"
> + check_device(option, device)
> +
> +if args.unset:
> + option = args.unset
> + value = ""
> + check(CONFIG_FILE, option, value, True)
> --
> 2.14.3
>