On Fri, Aug 17, 2018 at 8:10 AM, Dave Young <dyoung(a)redhat.com> wrote:
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.
I will work on the same.
BTW, a manpage is needed.
Man page patch is ready, I will send it soon.
Anyway, thanks for the patch.
Welcome
>>
>> 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
>>