From 6e2c7415b6469aa12391f0f60fb3f0a208129de2 Mon Sep 17 00:00:00 2001 From: Mark Irish Date: Wed, 18 Nov 2020 15:44:41 -0600 Subject: [PATCH 01/31] Initial attempt Initial rough attempt at converting chroot_setup.sh to chroot_setup.py Currently has a bugs, may not run, but every function save one has been converted to rough Python Signed-off-by: Mark Irish --- chroot_setup.py | 373 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 373 insertions(+) create mode 100644 chroot_setup.py diff --git a/chroot_setup.py b/chroot_setup.py new file mode 100644 index 0000000..1e0cdb8 --- /dev/null +++ b/chroot_setup.py @@ -0,0 +1,373 @@ +#!/QOpenSys/pkgs/bin/python3 + +import argparse +import os +import logging +import Template from string +from enum import Enum + +parser = argparse.ArgumentParser() +# positional arguments +parser.add_argument("chroot_directory", metavar="CHROOT_DIRECTORY", help="TODO: some help text") +parser.add_argument("chroot_type", metavar="CHROOT_TYPE", help="TODO: some help text", nargs="?") +# optional arguments +parser.add_argument("-g", dest='globals', nargs='*', metavar="", help="TODO: global variable") +parser.add_argument("-i", dest='yum_installs' nargs='*' metavar="", help="TODO: yum install") +parser.add_argument("-y", dest='auto_yes', metavar="", help="TODO: auto yes") +parser.add_argument("-v", dest='verbose', metavar="", help="TODO: verbose output") +args = parser.parse_args() +parser.parse_args() + +print(""" + ##### # # ###### ####### ####### ####### + # # # # # # # # # # # + # # # # # # # # # # + # ####### ###### # # # # # + # # # # # # # # # # + # # # # # # # # # # # + ##### # # # # ####### ####### # + + ##### ####### ####### # # ###### + # # # # # # # # + # # # # # # # + ##### ##### # # # ###### + # # # # # # + # # # # # # # + ##### ####### # ##### # +""") + +CHROOT_DEBUG : bool = False + +print(args.chroot_directory) + +# TODO: documentation +def chroot_mkdir ( dir: str ): + # TODO: fix print statement + print('os.mkdirs(' + args.chroot_directory + dir + ', exist_ok=True)') + if (CHROOT_DEBUG == False): + os.mkdirs(args.chroot_directory + dir, exist_ok=True) + +# TODO: documentation +# Function should occur inside a chroot +def chroot_ln (target: str, link_name: str): + # TODO: fix print statement + printf('chroot $CHROOT_DIR ln -sf $1 $2') + if (CHROOT_DEBUG == False): + # TODO: check that we don't have to go into the chroot. I suspect we might + os.symlink(target, link_name, dir_fd=args.chroot_directory) + +# TODO: documentation +# function occurs OUTSIDE chroot +# def chroot_ln_rel (target: str, link_name: str): +# mydir = os.path.dirname(target) +# mybase = os.path.basename(target) +# if (CHROOT_DEBUG == False): + +# relname=$(ls -l $1 | awk '{print $(NF)}') +# else +# relname="../../testing/$1" +# fi +# echo "cd $CHROOT_DIR$mydir" +# echo "ln -sf $relname $mybase" +# if (($CHROOT_DEBUG==0)); then +# here=$(pwd) +# cd $CHROOT_DIR$mydir +# ln -sf $relname $mybase +# cd $here +# fi +# } + +# TODO: documentation +# function occurs OUTSIDE chroot +def chroot_ln_fix_rel(target: str, link_name: str): + mydir = os.path.dirname(target) + mybase = os.path.basename(target) + print('cd ' + args.chroot_directory + mydir) + print('ln ' + link_name + ' ' + mybase) + + if (CHROOT_DEBUG == False): + here = os.getcwd() + os.chdir(args.chroot_directory + mydir) + os.symlink(target, link_name) + ln -sf $relname $mybase + os.chdir(here) + + +# TODO: documentation +def chroot_mknod (node: str, type: str, major, minor) { + print("mknod $CHROOT_DIR$1 $2 $3 $4") + if (CHROOT_DEBUG == False): + os.mknod(args.chroot_directory + node, type, major, minor) + # /QOpenSys/usr/sbin/mknod $CHROOT_DIR$1 $2 $3 $4 +} + +# TODO: documentation +def chroot_cp ( source: str ): + print("cp $1 $CHROOT_DIR$1") + if (CHROOT_DEBUG == False): + shutil.copy(source, args.chroot_directory + source) + +# TODO: documentation +def chroot_cp_dir ( source: str ): + print("cp -R $1/* $CHROOT_DIR$1/.") + # TODO: Why mkdir before checking debug? + chroot_mkdir(source) + if (CHROOT_DEBUG == False): + shutil.copytree(source, args.chroot_directory + source) + + +def chroot_chmod (mode, file) + # TODO: change + printf("chroot $CHROOT_DIR /QOpenSys/usr/bin/bsh -c \"chmod $1 $2\"") + if (CHROOT_DEBUG == False): + os.chmod(args.chroot_directory + file, int(mode), 8) + +def chroot_chmod_dir (mode, path) { + for root, dirs, files in os.walk(args.chroot_directory + path): + for dir in dirs: + os.chmod(os.path.join(root, dir), int(mode, 8)) + for file in files: + os.chmod(os.path.join(root, file), int(mode, 8)) + +def chroot_chown (user: str, file: str) + # TODO: change + printf("chroot $CHROOT_DIR /QOpenSys/usr/bin/bsh -c \"chmod $1 $2\"") + if (CHROOT_DEBUG == False): + os.chown(args.chroot_directory + file, user) + +#TODO: documentation +def chroot_chown_dir (user: str , path: str) { + for root, dirs, files in os.walk(args.chroot_directory + path): + for dir in dirs: + os.chown(os.path.join(root, dir), user) + for file in files: + os.chown(os.path.join(root, file), user) + +# TODO: documentation +def chroot_system(line: str): + line = line.rstrip() + print('system -i "' + line + '"') + if (CHROOT_DEBUG == False): + os.system('system -i "' + line + '"') + +# TODO: documentation +def chroot_sh(line: str): + print(line) + if (CHROOT_DEBUG == False): + os.system(line) + +action_dictionary = { + ':file' : chroot_setup, + ':mkidr' : chroot_mkdir, # done + ':ln_fix_rel' : chroot_ln_fix_rel, # done + ':ln_rel' : chroot_ln_rel, # done + ':ln' : chroot_ln, # done + ':mknod' : chroot_mknod, # done + ':cp_dir' : chroot_cp_dir, # done + ':cp' : chroot_cp, # done + ':chmod_dir' : chroot_chmod_dir, # done + ':chmod' : chroot_chmod, # done + ':chown_dir' : chroot_chown_dir, # done + ':chown' : chroot_chown, # done + ':system' : chroot_system, + ':sh' : chroot_sh +} + +def chroot_setup (chroot_lst): + lst_file = open(chroot_lst, 'r') + action = None + + # Iterate over all lines in the file, executing actions where encountered + for line in lst_file: + line = line.strip() + + # Blank line + if not line: + # print('empty') + + # Comment + else if line.startswith('#'): + # print('comment') + + # Determine action + else if line.startswith(':'): + action = action_dictionary[line] + + # Execute action + else: + if action not None: + action(line) + +# TODO: documentation +def initial_check (): + if (os.path.exists('/QOpenSys/usr/bin')): + CHROOT_DEBUG = False + PATH='/QOpenSys/usr/bin:/QOpenSys/usr/sbin:' + LIBPATH='/QOpenSys/usr/lib' + os.environ['PATH'] = PATH + os.environ['LIBPATH'] = LIBPATH + print("**********************") + print("Live IBM i session (changes made).") + print("**********************") + + if (ags.verbose): + print('PATH=' + PATH) + print('LIBPATH=' + LIBPATH) + + else: + CHROOT_DEBUG = True + print("**********************") + print("Not IBM i, no action is taken (debug flow purpose only).") + print("**********************") + # exit -1 + + +def yum_install(package_list: list): + os.environ["LIBPATH"] = '/QOpenSys/pkgs/lib:/QOpenSys/usr/lib' + install_template = Template('/QOpenSys/pkgs/bin/yum $yes --installroot=$chroot_dir install $package') + auto_yes = '-y' if args.auto_yes else '' + for package in package_list: + command = install_template.substitute(yes=auto_yes, chroot_dir=args.chroot_directory, package=package) + logger.debug(command) + os.system(command) + +# +# MAIN +# + +lst = 0 +ops = 0 +qsys = 0 +CHROOT_DIR = "" +CHROOT_LIST = "" +SCRIPT_DIR = os.path.dirname(os.readlink(args.chroot_directory)) + "/config" + +# Didn't implement all of the checks, argparse can do that + +intial_check() + +# This is done because the arg may be a relative path name. +# Need to be done before any 'cd' +TEMP_DIR = os.readlink(args.chroot_directory) + +logger.debug("Scipt Dir: " + SCRIPT_DIR) +os.chdir(SCRIPT_DIR) +logger.debug("PWD: " + os.getcwd()) + +if not TEMP_DIR.startswith('/QOpenSys/'): + print("\nERROR: [CHROOT DIRECTORY] Must begin with /QOpenSys/...\n") + parser.print_help + sys.exit(-2) + +CHROOT_DIR = TEMP_DIR + + +if not os.path.isdir(CHROOT_DIR): + print(CHROOT_DIR + " does not exist.") + os.mkdir(CHROOT_DIR) + # TODO: Check creation +else: + if not args.auto_yes + print(CHROOT_DIR + " directory already exists") + val = input("Would you like to continue chroot setup? [y/N]") + if not val == "y": + print("Bye") + sys.exit(-4) + else: + # continues automatically + + +## CHANGE +# Validate CHROOT TYPE Argument(s) +if not args.chroot_type: + # Only chroot_directory was provided to the script: + # Ask if minimal with includes chroot is desired + if not args.auto_yes: + val = input("Would you like to create a minimal chroot w/ includes @ " + CHROOT_DIR + "? [y/N]:") + if not val == "y": + print("Specify your desired [CHROOT TYPE]") + parser.print_help + sys.exit(-5) + + mylist = [] + mylist.append(SCRIPT_DIR + "/chroot_includes.lst") + mylist.append(SCRIPT_DIR + "/chroot_minimal.lst") + +else: + # If chroot types were specified, then use those + for arg in args.chroot_type + print("Chroot type is: " + arg) + # TODO: I think this is line with the shell script, but what about random + # list names that might include 'ops' in them? + if ("ops" in arg): + + # verify a deprecated OPS file was not specified + print("OPS has been depricated, and replaced with YUM Packages. Run $0 with a valid [CHROOT TYPE]") + parser.print_help + sys.exit(-6) + + CHROOT_LIST = arg + + # add chroot prefix if it doesn't exist + if not CHROOT_LIST.startswith('chroot'): + CHROOT_LIST = 'chroot_' + CHROOT_LIST + + # check that the .lst file name was given + if not CHROOT_LIST.endswith('.lst') + CHROOT_LIST = CHROOT_LIST + '.lst' + + # check that the .lst file exists + if not os.path.isfile(CHROOT_LIST): + print(CHROOT_LIST + " cannot be found in " os.cwd) + sys.exit(-7) + else: + # append file name to end of list + mylist.append(os.readlink(CHROOT_LIST)) + +logger.debug("Number of elements in the list: " + len(mylist)) +logger.debug("List contents: " + mylist) #TODO: doubt this works + +# convert any global variables passed from a list of string "KEY=VALUE" to a +# dictionary holding "KEY": "VALUE" +globals_dictionary = {} +if args.globals: + for global_var in args.globals: + global_tokens = global_var.split('=') + globals_dictionary[global_tokens[0]] = global_tokens[1] + +for chroot_file in mylist: + print("=====================================") + print("setting up based on " + chroot_file) + print("=====================================") + + for key in globals_dictionary: + os.environ[key] = globals_dictionary[key] + + chroot_setup(chroot) + + for key in globals_dictionary: + del os.environ[key] + +os.makedirs(args.chroot_directory + '/QOpenSys/etc', exit_ok=True) +etc_profile = (args.chroot_directory + '/QOpenSys/etc/profile') +if not os.path.isfile(etc_profile): + print('Priming /QOpenSys/etc/profile') + etc_file = open(etc_profile, 'a') + etc_file.write('PATH=/QOpenSys/pkgs/bin:$PATH\n') + etc_file.write('export PATH\n') + etc_file.write('OBJECT_MODE=64\n') + etc_file.write('export OBJECT_MODE\n') + +# perform installs if set +yum_install(args.yum_installs) + +print(""" + +Done creating your chroot! + +To enter your chroot +Run: chroot """ + args.chroot_directory + """ /QOpenSys/usr/bin/sh + +To set up your PATH to pick up RPM packages once inside your chroot +Run: . /QOpenSys/etc/profile +""") \ No newline at end of file From 57be2ef025bcd7daa9428281106ba86e167ebaa1 Mon Sep 17 00:00:00 2001 From: Mark Irish Date: Mon, 14 Dec 2020 20:55:09 -0600 Subject: [PATCH 02/31] Continue fixing new Python chroot_setup Fix all build and runtime errors Ensure that basic functionality works Signed-off-by: Mark Irish --- chroot_setup | 420 ++++++++++++++++++++++++++++++++++++++++++++++++ chroot_setup.py | 373 ------------------------------------------ 2 files changed, 420 insertions(+), 373 deletions(-) create mode 100644 chroot_setup delete mode 100644 chroot_setup.py diff --git a/chroot_setup b/chroot_setup new file mode 100644 index 0000000..46e694b --- /dev/null +++ b/chroot_setup @@ -0,0 +1,420 @@ +#!/QOpenSys/pkgs/bin/python3 + +import argparse +import os +import sys +import logging +import stat +from string import Template +from enum import Enum + +parser = argparse.ArgumentParser() +# positional arguments +parser.add_argument("chroot_directory", metavar="CHROOT_DIRECTORY", help="TODO: some help text") +parser.add_argument("chroot_type", metavar="CHROOT_TYPE", help="TODO: some help text", nargs="?") +# optional arguments +parser.add_argument("-g", dest='globals', nargs='*', metavar="", help="TODO: global variable") +parser.add_argument("-i", dest='yum_installs', nargs='*', metavar="", help="TODO: yum install") +parser.add_argument("-y", dest='auto_yes', action='store_true', help="TODO: auto yes") +parser.add_argument("-v", dest='verbose', action='store_true', help="TODO: verbose output") +args = parser.parse_args() +parser.parse_args() + +print(""" + ##### # # ###### ####### ####### ####### + # # # # # # # # # # # + # # # # # # # # # # + # ####### ###### # # # # # + # # # # # # # # # # + # # # # # # # # # # # + ##### # # # # ####### ####### # + + ##### ####### ####### # # ###### + # # # # # # # # + # # # # # # # + ##### ##### # # # ###### + # # # # # # + # # # # # # # + ##### ####### # ##### # +""") + +CHROOT_DEBUG : bool = True + +print(args.chroot_directory) + +# :mkdir +# Make a directory inside the chroot, as well as all intermediary directories +def chroot_mkdir (dir: str): + print(f'os.mkdirs({args.chroot_directory + dir}, exist_ok=True)') + if (CHROOT_DEBUG == False): + os.mkdirs(args.chroot_directory + dir, exist_ok=True) + +# :ln +# Create a symlink inside a chroot, so all absolute paths are absolute to the +# chroot's root +def chroot_ln (line: str): + ln_command = line.split() + assert len(ln_command) == 2, ":ln entry expects 2 arguments!" + target = ln_command[0] + link_name = ln_command[1] + print(f'os.symlink({target}, {link_name}, dir_fd={args.chroot_directory})') + if (CHROOT_DEBUG == False): + # TODO: check that we don't have to go into the chroot. I suspect we might + os.symlink(target, link_name, dir_fd=args.chroot_directory) + +# TODO: documentation +# function occurs OUTSIDE chroot +def chroot_ln_rel (line: str): + print() + # mydir = os.path.dirname(target) + # mybase = os.path.basename(target) + # if (CHROOT_DEBUG == False): + # relname=$(ls -l $1 | awk '{print $(NF)}') + # else + # relname="../../testing/$1" + # fi + # echo "cd $CHROOT_DIR$mydir" + # echo "ln -sf $relname $mybase" + # if (($CHROOT_DEBUG==0)); then + # here=$(pwd) + # cd $CHROOT_DIR$mydir + # ln -sf $relname $mybase + # cd $here + +# TODO: documentation +# function occurs OUTSIDE chroot +def chroot_ln_fix_rel (line: str): + ln_command = line.split() + assert len(mknod_command) == 4, "ln_fix_rel command expects 2 arguments!" + mydir = os.path.dirname(target) # TODO: how does this work + mybase = os.path.basename(target) + print(f'os.chdir({args.chroot_directory + mydir})') + print(f'os.symlink{link_name}, {target})') + print(f'os.chdir({here})') + + if (CHROOT_DEBUG == False): + here = os.getcwd() + os.chdir(args.chroot_directory + mydir) + os.symlink(target, link_name) + os.chdir(here) + + +# :mknod +def chroot_mknod (line: str): + # We are passed a mknod terminal commmand. Need to parse it to make it work + # with os.mknod. + mknod_command = line.split() + assert len(mknod_command) == 4, "mknod command expects 4 arguments!" + node: str = mknod_command[0] + if (mknod_command[1] == 'p'): + mode = 0o644 | stat.S_IFIFO + elif (mknod_command[1] == 'b'): + mode = 0o644 | stat.S_IFBLK + elif (mknod_command[1] == 'c'): + mode = 0o644 | stat.S_IFCHR + else: + print("Unrecognized mknod type; Valid types are 'p', 'b', and 'c'") + sys.exit(-6) + major = mknod_command[2] + minor = mknod_command[3] + + print(f"os.mknod({args.chroot_directory + node}, {mode}, {major}, {minor})") + if (CHROOT_DEBUG == False): + os.mknod(args.chroot_directory + node, mode, major, minor) + +# TODO: documentation +def chroot_cp (line: str): + print(f"shutil.copy({line}, {args.chroot_directory + line})") + if (CHROOT_DEBUG == False): + shutil.copy(source, args.chroot_directory + source) + +# TODO: documentation +def chroot_cp_dir ( source: str ): + print("cp -R $1/* $CHROOT_DIR$1/.") + # TODO: Why mkdir before checking debug? + chroot_mkdir(source) + if (CHROOT_DEBUG == False): + shutil.copytree(source, args.chroot_directory + source) + + +def chroot_chmod (line: str): + chmod_command = line.split() + assert len(chmod_command) == 2, "chmod command expects 2 arguments!" + mode = int(chmod_command[0], 8) + chmod_file = args.chroot_directory + chmod_command[1] + printf(f"os.chmod({chmod_file}, {mode})") + if (CHROOT_DEBUG == False): + os.chmod(chmod_file, mode) + +def chroot_chmod_dir (line: str): + chmod_command = line.split() + assert len(chmod_command) == 2, "chmod command expects 2 arguments!" + mode = int(chmod_command[0], 8) + chmod_file = args.chroot_directory + chmod_command[1] + for root, dirs, files in os.walk(args.chroot_directory + chmod_file): + for dir in dirs: + print(f'os.chmod({os.path.join(root, dir)}, {int(mode, 8)})') + if (CHROOT_DEBUG == FALSE): + os.chmod(os.path.join(root, dir), int(mode, 8)) + for file in files: + print(f'os.chmod({os.path.join(root, chmod_file)}, {int(mode, 8)})') + if (CHROOT_DEBUG == FALSE): + os.chmod(os.path.join(root, chmod_file), int(mode, 8)) + +# :chown +def chroot_chown (line: str): + # TODO: change + chown_command = line.split() + assert len(chown_command) == 2, ":chown command expect 2 arguments!" + user = chown_command[0] + chown_file = args.chroot_directory + chown_command[1] + printf(f"os.chown({chown_file}, {user})") + if (CHROOT_DEBUG == False): + os.chown(args.chroot_directory + file, user) + +# :chown_dir +def chroot_chown_dir (line: str): + chown_command = line.split() + assert len(chown_command) == 2, ":chown_dir command expect 2 arguments!" + user = chown_command[0] + chown_directory = args.chroot_directory + chown_command[1] + for root, dirs, files in os.walk(args.chroot_directory + chown_directory): + for dir in dirs: + printf(f'os.chown({os.path.join(root, dir)}, {user})') + if (CHROOT_DEBUG == False): + os.chown(os.path.join(root, dir), user) + for file in files: + printf(f'os.chown({os.path.join(root, file)}, {user})') + if (CHROOT_DEBUG == False): + os.chown(os.path.join(root, file), user) + +# :system +# Executes a line from a .lst file using the /QOpenSys/usr/bin/system utility +def chroot_system(line: str): + line = line.rstrip() + print('system -i "' + line + '"') + if (CHROOT_DEBUG == False): + os.system('system -i "' + line + '"') + +# :sh +# Executes a line from a .lst file using Pythons os.system function, which is +# run "by calling the Standard C function system()." +def chroot_sh(line: str): + print(line) + if (CHROOT_DEBUG == False): + os.system(line) + +# :file +# Parses and executes additional .lst files +def chroot_setup (chroot_lst): + lst_file = open(chroot_lst, 'r') + action = None + + # Iterate over all lines in the file, executing actions where encountered + for line in lst_file: + line = line.strip() + + # Skip blank lines and comments + if not line or line.startswith('#'): + continue + + # Determine action + elif line.startswith(':'): + action = action_dictionary[line] + + # Execute action + else: + if action is not None: + action(line) + +action_dictionary = { + ':file' : chroot_setup, + ':mkdir' : chroot_mkdir, # done + ':ln_fix_rel' : chroot_ln_fix_rel, # done + ':ln_rel' : chroot_ln_rel, # done + ':ln' : chroot_ln, # done + ':mknod' : chroot_mknod, # done + ':cp_dir' : chroot_cp_dir, # done + ':cp' : chroot_cp, # done + ':chmod_dir' : chroot_chmod_dir, # done + ':chmod' : chroot_chmod, # done + ':chown_dir' : chroot_chown_dir, # done + ':chown' : chroot_chown, # done + ':system' : chroot_system, # done + ':sh' : chroot_sh # done +} + +# TODO: documentation +def initial_check(): + if (os.uname().sysname == 'OS400'): + # CHROOT_DEBUG = False + PATH='/QOpenSys/pkgs/bin:/QOpenSys/pkgs/sbin:/QOpenSys/usr/bin:/QOpenSys/usr/sbin:' + LIBPATH='/QOpenSys/pkgs/lib:/QOpenSys/usr/lib' + os.environ['PATH'] = PATH + os.environ['LIBPATH'] = LIBPATH + print("**********************") + print("Live IBM i session (changes made).") + print("**********************") + + if (args.verbose): + print('PATH=' + PATH) + print('LIBPATH=' + LIBPATH) + + else: + # CHROOT_DEBUG = True + print("**********************") + print("Not IBM i, no action is taken (debug flow purpose only).") + print("**********************") + # exit -1 + + +def yum_install(package_list: list): + os.environ["LIBPATH"] = '/QOpenSys/pkgs/lib:/QOpenSys/usr/lib' + install_template = Template('/QOpenSys/pkgs/bin/yum $yes --installroot=$chroot_dir install $package') + auto_yes = '-y' if args.auto_yes else '' + for package in package_list: + command = install_template.substitute(yes=auto_yes, chroot_dir=args.chroot_directory, package=package) + logging.debug(command) + os.system(command) + +# +# MAIN +# +if __name__ == '__main__': + lst = 0 + ops = 0 + qsys = 0 + CHROOT_DIR = "" + CHROOT_LIST = "" + SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__)) + "/config" + + print(SCRIPT_DIR) + + auto_yes = args.auto_yes + + + initial_check() + + # This is done because the arg may be a relative path name. + # Need to be done before any 'cd' + TEMP_DIR = os.path.realpath(args.chroot_directory) + print(TEMP_DIR) + + # if -v was passed, need to turn logging to DEBUG so all logging messages in the + # code are printed + if (args.verbose): + logging.basicConfig(level=logging.DEBUG) + + logging.debug("Script directory: " + SCRIPT_DIR) + os.chdir(SCRIPT_DIR) + logging.debug("PWD: " + os.getcwd()) + + if not TEMP_DIR.startswith('/QOpenSys/'): + print("\nERROR: [CHROOT DIRECTORY] Must begin with /QOpenSys/...\n") + parser.print_help + sys.exit(-2) + + CHROOT_DIR = TEMP_DIR + + + if not os.path.isdir(CHROOT_DIR): + print(CHROOT_DIR + " does not exist.") + logging.debug(f"Creating directory at {CHROOT_DIR}") + os.mkdir(CHROOT_DIR) + # TODO: Check creation + else: + if not auto_yes: + print(CHROOT_DIR + " directory already exists") + val = input("Would you like to continue chroot setup? [y/N]") + if not val == "y": + print("Bye") + sys.exit(-4) + + + ## CHANGE + # Validate CHROOT TYPE Argument(s) + if not args.chroot_type: + # Only chroot_directory was provided to the script: + # Ask if minimal with includes chroot is desired + if not auto_yes: + val = input("Would you like to create a minimal chroot w/ includes @ " + CHROOT_DIR + "? [y/N]:") + if not val == "y": + print("Specify your desired [CHROOT TYPE]") + parser.print_help + sys.exit(-5) + + mylist = [] + mylist.append(SCRIPT_DIR + "/chroot_includes.lst") + mylist.append(SCRIPT_DIR + "/chroot_minimal.lst") + + else: + # If chroot types were specified, then use those + for arg in args.chroot_type: + print("Chroot type is: " + arg) + + CHROOT_LIST = arg + + # add chroot prefix if it doesn't exist + if not CHROOT_LIST.startswith('chroot'): + CHROOT_LIST = 'chroot_' + CHROOT_LIST + + # check that the .lst file name was given + if not CHROOT_LIST.endswith('.lst'): + CHROOT_LIST = CHROOT_LIST + '.lst' + + # check that the .lst file exists + if not os.path.isfile(CHROOT_LIST): + print(f"{CHROOT_LIST} cannot be found in {os.cwd}") + sys.exit(-7) + else: + # append file name to end of list + mylist.append(os.readlink(CHROOT_LIST)) + + logging.debug(f"Number of elements in the list: {len(mylist)}") + logging.debug(f"List contents: {mylist}") + + # convert any global variables passed from a list of string "KEY=VALUE" to a + # dictionary holding "KEY": "VALUE" + globals_dictionary = {} + if args.globals: + for global_var in args.globals: + global_tokens = global_var.split('=') + globals_dictionary[global_tokens[0]] = global_tokens[1] + + for chroot_file in mylist: + print("=====================================") + print("setting up based on " + chroot_file) + print("=====================================") + + for key in globals_dictionary: + os.environ[key] = globals_dictionary[key] + + chroot_setup(chroot_file) + + for key in globals_dictionary: + del os.environ[key] + + os.makedirs(args.chroot_directory + '/QOpenSys/etc', exist_ok=True) + etc_profile = (args.chroot_directory + '/QOpenSys/etc/profile') + if not os.path.isfile(etc_profile): + print('Priming /QOpenSys/etc/profile') + etc_file = open(etc_profile, 'a') + etc_file.write('PATH=/QOpenSys/pkgs/bin:$PATH\n') + etc_file.write('export PATH\n') + etc_file.write('OBJECT_MODE=64\n') + etc_file.write('export OBJECT_MODE\n') + + # perform installs if set + if args.yum_installs is not None: + yum_install(args.yum_installs) + + print(f""" + + Done creating your chroot! + + To enter your chroot + Run: chroot {args.chroot_directory} /QOpenSys/usr/bin/sh + + To set up your PATH to pick up RPM packages once inside your chroot + Run: . /QOpenSys/etc/profile + """) diff --git a/chroot_setup.py b/chroot_setup.py deleted file mode 100644 index 1e0cdb8..0000000 --- a/chroot_setup.py +++ /dev/null @@ -1,373 +0,0 @@ -#!/QOpenSys/pkgs/bin/python3 - -import argparse -import os -import logging -import Template from string -from enum import Enum - -parser = argparse.ArgumentParser() -# positional arguments -parser.add_argument("chroot_directory", metavar="CHROOT_DIRECTORY", help="TODO: some help text") -parser.add_argument("chroot_type", metavar="CHROOT_TYPE", help="TODO: some help text", nargs="?") -# optional arguments -parser.add_argument("-g", dest='globals', nargs='*', metavar="", help="TODO: global variable") -parser.add_argument("-i", dest='yum_installs' nargs='*' metavar="", help="TODO: yum install") -parser.add_argument("-y", dest='auto_yes', metavar="", help="TODO: auto yes") -parser.add_argument("-v", dest='verbose', metavar="", help="TODO: verbose output") -args = parser.parse_args() -parser.parse_args() - -print(""" - ##### # # ###### ####### ####### ####### - # # # # # # # # # # # - # # # # # # # # # # - # ####### ###### # # # # # - # # # # # # # # # # - # # # # # # # # # # # - ##### # # # # ####### ####### # - - ##### ####### ####### # # ###### - # # # # # # # # - # # # # # # # - ##### ##### # # # ###### - # # # # # # - # # # # # # # - ##### ####### # ##### # -""") - -CHROOT_DEBUG : bool = False - -print(args.chroot_directory) - -# TODO: documentation -def chroot_mkdir ( dir: str ): - # TODO: fix print statement - print('os.mkdirs(' + args.chroot_directory + dir + ', exist_ok=True)') - if (CHROOT_DEBUG == False): - os.mkdirs(args.chroot_directory + dir, exist_ok=True) - -# TODO: documentation -# Function should occur inside a chroot -def chroot_ln (target: str, link_name: str): - # TODO: fix print statement - printf('chroot $CHROOT_DIR ln -sf $1 $2') - if (CHROOT_DEBUG == False): - # TODO: check that we don't have to go into the chroot. I suspect we might - os.symlink(target, link_name, dir_fd=args.chroot_directory) - -# TODO: documentation -# function occurs OUTSIDE chroot -# def chroot_ln_rel (target: str, link_name: str): -# mydir = os.path.dirname(target) -# mybase = os.path.basename(target) -# if (CHROOT_DEBUG == False): - -# relname=$(ls -l $1 | awk '{print $(NF)}') -# else -# relname="../../testing/$1" -# fi -# echo "cd $CHROOT_DIR$mydir" -# echo "ln -sf $relname $mybase" -# if (($CHROOT_DEBUG==0)); then -# here=$(pwd) -# cd $CHROOT_DIR$mydir -# ln -sf $relname $mybase -# cd $here -# fi -# } - -# TODO: documentation -# function occurs OUTSIDE chroot -def chroot_ln_fix_rel(target: str, link_name: str): - mydir = os.path.dirname(target) - mybase = os.path.basename(target) - print('cd ' + args.chroot_directory + mydir) - print('ln ' + link_name + ' ' + mybase) - - if (CHROOT_DEBUG == False): - here = os.getcwd() - os.chdir(args.chroot_directory + mydir) - os.symlink(target, link_name) - ln -sf $relname $mybase - os.chdir(here) - - -# TODO: documentation -def chroot_mknod (node: str, type: str, major, minor) { - print("mknod $CHROOT_DIR$1 $2 $3 $4") - if (CHROOT_DEBUG == False): - os.mknod(args.chroot_directory + node, type, major, minor) - # /QOpenSys/usr/sbin/mknod $CHROOT_DIR$1 $2 $3 $4 -} - -# TODO: documentation -def chroot_cp ( source: str ): - print("cp $1 $CHROOT_DIR$1") - if (CHROOT_DEBUG == False): - shutil.copy(source, args.chroot_directory + source) - -# TODO: documentation -def chroot_cp_dir ( source: str ): - print("cp -R $1/* $CHROOT_DIR$1/.") - # TODO: Why mkdir before checking debug? - chroot_mkdir(source) - if (CHROOT_DEBUG == False): - shutil.copytree(source, args.chroot_directory + source) - - -def chroot_chmod (mode, file) - # TODO: change - printf("chroot $CHROOT_DIR /QOpenSys/usr/bin/bsh -c \"chmod $1 $2\"") - if (CHROOT_DEBUG == False): - os.chmod(args.chroot_directory + file, int(mode), 8) - -def chroot_chmod_dir (mode, path) { - for root, dirs, files in os.walk(args.chroot_directory + path): - for dir in dirs: - os.chmod(os.path.join(root, dir), int(mode, 8)) - for file in files: - os.chmod(os.path.join(root, file), int(mode, 8)) - -def chroot_chown (user: str, file: str) - # TODO: change - printf("chroot $CHROOT_DIR /QOpenSys/usr/bin/bsh -c \"chmod $1 $2\"") - if (CHROOT_DEBUG == False): - os.chown(args.chroot_directory + file, user) - -#TODO: documentation -def chroot_chown_dir (user: str , path: str) { - for root, dirs, files in os.walk(args.chroot_directory + path): - for dir in dirs: - os.chown(os.path.join(root, dir), user) - for file in files: - os.chown(os.path.join(root, file), user) - -# TODO: documentation -def chroot_system(line: str): - line = line.rstrip() - print('system -i "' + line + '"') - if (CHROOT_DEBUG == False): - os.system('system -i "' + line + '"') - -# TODO: documentation -def chroot_sh(line: str): - print(line) - if (CHROOT_DEBUG == False): - os.system(line) - -action_dictionary = { - ':file' : chroot_setup, - ':mkidr' : chroot_mkdir, # done - ':ln_fix_rel' : chroot_ln_fix_rel, # done - ':ln_rel' : chroot_ln_rel, # done - ':ln' : chroot_ln, # done - ':mknod' : chroot_mknod, # done - ':cp_dir' : chroot_cp_dir, # done - ':cp' : chroot_cp, # done - ':chmod_dir' : chroot_chmod_dir, # done - ':chmod' : chroot_chmod, # done - ':chown_dir' : chroot_chown_dir, # done - ':chown' : chroot_chown, # done - ':system' : chroot_system, - ':sh' : chroot_sh -} - -def chroot_setup (chroot_lst): - lst_file = open(chroot_lst, 'r') - action = None - - # Iterate over all lines in the file, executing actions where encountered - for line in lst_file: - line = line.strip() - - # Blank line - if not line: - # print('empty') - - # Comment - else if line.startswith('#'): - # print('comment') - - # Determine action - else if line.startswith(':'): - action = action_dictionary[line] - - # Execute action - else: - if action not None: - action(line) - -# TODO: documentation -def initial_check (): - if (os.path.exists('/QOpenSys/usr/bin')): - CHROOT_DEBUG = False - PATH='/QOpenSys/usr/bin:/QOpenSys/usr/sbin:' - LIBPATH='/QOpenSys/usr/lib' - os.environ['PATH'] = PATH - os.environ['LIBPATH'] = LIBPATH - print("**********************") - print("Live IBM i session (changes made).") - print("**********************") - - if (ags.verbose): - print('PATH=' + PATH) - print('LIBPATH=' + LIBPATH) - - else: - CHROOT_DEBUG = True - print("**********************") - print("Not IBM i, no action is taken (debug flow purpose only).") - print("**********************") - # exit -1 - - -def yum_install(package_list: list): - os.environ["LIBPATH"] = '/QOpenSys/pkgs/lib:/QOpenSys/usr/lib' - install_template = Template('/QOpenSys/pkgs/bin/yum $yes --installroot=$chroot_dir install $package') - auto_yes = '-y' if args.auto_yes else '' - for package in package_list: - command = install_template.substitute(yes=auto_yes, chroot_dir=args.chroot_directory, package=package) - logger.debug(command) - os.system(command) - -# -# MAIN -# - -lst = 0 -ops = 0 -qsys = 0 -CHROOT_DIR = "" -CHROOT_LIST = "" -SCRIPT_DIR = os.path.dirname(os.readlink(args.chroot_directory)) + "/config" - -# Didn't implement all of the checks, argparse can do that - -intial_check() - -# This is done because the arg may be a relative path name. -# Need to be done before any 'cd' -TEMP_DIR = os.readlink(args.chroot_directory) - -logger.debug("Scipt Dir: " + SCRIPT_DIR) -os.chdir(SCRIPT_DIR) -logger.debug("PWD: " + os.getcwd()) - -if not TEMP_DIR.startswith('/QOpenSys/'): - print("\nERROR: [CHROOT DIRECTORY] Must begin with /QOpenSys/...\n") - parser.print_help - sys.exit(-2) - -CHROOT_DIR = TEMP_DIR - - -if not os.path.isdir(CHROOT_DIR): - print(CHROOT_DIR + " does not exist.") - os.mkdir(CHROOT_DIR) - # TODO: Check creation -else: - if not args.auto_yes - print(CHROOT_DIR + " directory already exists") - val = input("Would you like to continue chroot setup? [y/N]") - if not val == "y": - print("Bye") - sys.exit(-4) - else: - # continues automatically - - -## CHANGE -# Validate CHROOT TYPE Argument(s) -if not args.chroot_type: - # Only chroot_directory was provided to the script: - # Ask if minimal with includes chroot is desired - if not args.auto_yes: - val = input("Would you like to create a minimal chroot w/ includes @ " + CHROOT_DIR + "? [y/N]:") - if not val == "y": - print("Specify your desired [CHROOT TYPE]") - parser.print_help - sys.exit(-5) - - mylist = [] - mylist.append(SCRIPT_DIR + "/chroot_includes.lst") - mylist.append(SCRIPT_DIR + "/chroot_minimal.lst") - -else: - # If chroot types were specified, then use those - for arg in args.chroot_type - print("Chroot type is: " + arg) - # TODO: I think this is line with the shell script, but what about random - # list names that might include 'ops' in them? - if ("ops" in arg): - - # verify a deprecated OPS file was not specified - print("OPS has been depricated, and replaced with YUM Packages. Run $0 with a valid [CHROOT TYPE]") - parser.print_help - sys.exit(-6) - - CHROOT_LIST = arg - - # add chroot prefix if it doesn't exist - if not CHROOT_LIST.startswith('chroot'): - CHROOT_LIST = 'chroot_' + CHROOT_LIST - - # check that the .lst file name was given - if not CHROOT_LIST.endswith('.lst') - CHROOT_LIST = CHROOT_LIST + '.lst' - - # check that the .lst file exists - if not os.path.isfile(CHROOT_LIST): - print(CHROOT_LIST + " cannot be found in " os.cwd) - sys.exit(-7) - else: - # append file name to end of list - mylist.append(os.readlink(CHROOT_LIST)) - -logger.debug("Number of elements in the list: " + len(mylist)) -logger.debug("List contents: " + mylist) #TODO: doubt this works - -# convert any global variables passed from a list of string "KEY=VALUE" to a -# dictionary holding "KEY": "VALUE" -globals_dictionary = {} -if args.globals: - for global_var in args.globals: - global_tokens = global_var.split('=') - globals_dictionary[global_tokens[0]] = global_tokens[1] - -for chroot_file in mylist: - print("=====================================") - print("setting up based on " + chroot_file) - print("=====================================") - - for key in globals_dictionary: - os.environ[key] = globals_dictionary[key] - - chroot_setup(chroot) - - for key in globals_dictionary: - del os.environ[key] - -os.makedirs(args.chroot_directory + '/QOpenSys/etc', exit_ok=True) -etc_profile = (args.chroot_directory + '/QOpenSys/etc/profile') -if not os.path.isfile(etc_profile): - print('Priming /QOpenSys/etc/profile') - etc_file = open(etc_profile, 'a') - etc_file.write('PATH=/QOpenSys/pkgs/bin:$PATH\n') - etc_file.write('export PATH\n') - etc_file.write('OBJECT_MODE=64\n') - etc_file.write('export OBJECT_MODE\n') - -# perform installs if set -yum_install(args.yum_installs) - -print(""" - -Done creating your chroot! - -To enter your chroot -Run: chroot """ + args.chroot_directory + """ /QOpenSys/usr/bin/sh - -To set up your PATH to pick up RPM packages once inside your chroot -Run: . /QOpenSys/etc/profile -""") \ No newline at end of file From 95b121997abf1f8857a6fa891fbd1203f6588071 Mon Sep 17 00:00:00 2001 From: Mark Irish Date: Tue, 15 Dec 2020 21:00:06 -0600 Subject: [PATCH 03/31] Major cleanup and testing Change all print statements to their Python functions Add documentation Implement chroot_ln_rel function Fix bugs Add help text --- chroot_setup | 156 +++++++++++++++++++++---------------- config/chroot_includes.lst | 1 - config/chroot_minimal.lst | 52 ++++++------- 3 files changed, 112 insertions(+), 97 deletions(-) diff --git a/chroot_setup b/chroot_setup index 46e694b..b704305 100644 --- a/chroot_setup +++ b/chroot_setup @@ -3,6 +3,7 @@ import argparse import os import sys +import shutil import logging import stat from string import Template @@ -10,13 +11,13 @@ from enum import Enum parser = argparse.ArgumentParser() # positional arguments -parser.add_argument("chroot_directory", metavar="CHROOT_DIRECTORY", help="TODO: some help text") -parser.add_argument("chroot_type", metavar="CHROOT_TYPE", help="TODO: some help text", nargs="?") +parser.add_argument("chroot_directory", metavar="CHROOT_DIRECTORY", help="The location of the chroot to be created") +parser.add_argument("chroot_type", metavar="CHROOT_TYPE", help="A list of .lst files to use for generating the chroot", nargs="?") # optional arguments -parser.add_argument("-g", dest='globals', nargs='*', metavar="", help="TODO: global variable") -parser.add_argument("-i", dest='yum_installs', nargs='*', metavar="", help="TODO: yum install") -parser.add_argument("-y", dest='auto_yes', action='store_true', help="TODO: auto yes") -parser.add_argument("-v", dest='verbose', action='store_true', help="TODO: verbose output") +parser.add_argument("-g", dest='globals', nargs='*', metavar="", help="Environment variables to set when creating the chroot") +parser.add_argument("-i", dest='yum_installs', nargs='*', metavar="", help="A list of packages for yum to install in the chroot") +parser.add_argument("-y", dest='auto_yes', action='store_true', help="Automatically answer yes to input prompts") +parser.add_argument("-v", dest='verbose', action='store_true', help="Print verbose output when running") args = parser.parse_args() parser.parse_args() @@ -38,74 +39,78 @@ print(""" ##### ####### # ##### # """) -CHROOT_DEBUG : bool = True +CHROOT_DEBUG : bool = False print(args.chroot_directory) # :mkdir # Make a directory inside the chroot, as well as all intermediary directories def chroot_mkdir (dir: str): - print(f'os.mkdirs({args.chroot_directory + dir}, exist_ok=True)') + print(f'os.makedirs({args.chroot_directory + dir}, exist_ok=True)') if (CHROOT_DEBUG == False): - os.mkdirs(args.chroot_directory + dir, exist_ok=True) + os.makedirs(args.chroot_directory + dir, exist_ok=True) # :ln -# Create a symlink inside a chroot, so all absolute paths are absolute to the -# chroot's root +# Create an absolute symlink. We don't have to go inside the chroot, since the +# links are resolved as they are used. The target doesn't even have to exist, +# Python won't check and therefore won't throw an error. def chroot_ln (line: str): ln_command = line.split() - assert len(ln_command) == 2, ":ln entry expects 2 arguments!" + assert len(ln_command) == 2, ":ln action expects 2 arguments!" target = ln_command[0] link_name = ln_command[1] - print(f'os.symlink({target}, {link_name}, dir_fd={args.chroot_directory})') + print(f'os.symlink({target}, {args.chroot_directory + link_name})') if (CHROOT_DEBUG == False): - # TODO: check that we don't have to go into the chroot. I suspect we might - os.symlink(target, link_name, dir_fd=args.chroot_directory) + os.symlink(target, args.chroot_directory + link_name) -# TODO: documentation -# function occurs OUTSIDE chroot +# :ln_rel +# Create a relative symlink in the chroot that mirrors a relative symlink that +# exists outside of the chroot. def chroot_ln_rel (line: str): - print() - # mydir = os.path.dirname(target) - # mybase = os.path.basename(target) - # if (CHROOT_DEBUG == False): - # relname=$(ls -l $1 | awk '{print $(NF)}') - # else - # relname="../../testing/$1" - # fi - # echo "cd $CHROOT_DIR$mydir" - # echo "ln -sf $relname $mybase" - # if (($CHROOT_DEBUG==0)); then - # here=$(pwd) - # cd $CHROOT_DIR$mydir - # ln -sf $relname $mybase - # cd $here - -# TODO: documentation -# function occurs OUTSIDE chroot + ln_command = line.split() + assert len(mknod_command) == 1, ":ln_fix_rel action expects 1 argument!" + directory = os.path.dirname(line) + basename = os.path.basename(line) + target = os.readlink(line) + here = os.getcwd() + print(f'os.chdir({args.chroot_directory + directory})') + print(f'os.symlink({target}, {basename})') + if (CHROOT_DEBUG == False): + os.chdir(args.chroot_directory + mydir) + os.symlink(target, basename) + os.chdir(here) + +# :ln +# Create a relative symlink inside of the chroot, specifying where the link +# should be pointed to. This means you can change a relative symlink you pass +# in, or simply create a relative symlink where one didn't exist before def chroot_ln_fix_rel (line: str): ln_command = line.split() - assert len(mknod_command) == 4, "ln_fix_rel command expects 2 arguments!" - mydir = os.path.dirname(target) # TODO: how does this work - mybase = os.path.basename(target) - print(f'os.chdir({args.chroot_directory + mydir})') - print(f'os.symlink{link_name}, {target})') + assert len(mknod_command) == 2, ":ln_fix_rel action expects 2 arguments!" + target = ln_command[1] + link_name = ln_command[2] + directory = os.path.dirname(link_name) + basename = os.path.basename(link_name) + here = os.getcwd() + print(f'os.chdir({args.chroot_directory + directory})') + print(f'os.symlink{target}, {basename})') print(f'os.chdir({here})') - if (CHROOT_DEBUG == False): - here = os.getcwd() os.chdir(args.chroot_directory + mydir) - os.symlink(target, link_name) + os.symlink(target, basename) os.chdir(here) - # :mknod +# Create a node with a given name, type, and major and minor number def chroot_mknod (line: str): # We are passed a mknod terminal commmand. Need to parse it to make it work # with os.mknod. mknod_command = line.split() assert len(mknod_command) == 4, "mknod command expects 4 arguments!" node: str = mknod_command[0] + + # mode is created by OR-ing the permissions with the type of node to be + # created if (mknod_command[1] == 'p'): mode = 0o644 | stat.S_IFIFO elif (mknod_command[1] == 'b'): @@ -115,28 +120,40 @@ def chroot_mknod (line: str): else: print("Unrecognized mknod type; Valid types are 'p', 'b', and 'c'") sys.exit(-6) + + # device major and minor numbers are created through os.makedev major = mknod_command[2] minor = mknod_command[3] + device = os.makedev(int(major), int(minor)) - print(f"os.mknod({args.chroot_directory + node}, {mode}, {major}, {minor})") + print(f"os.mknod({args.chroot_directory + node}, {mode}, {device})") if (CHROOT_DEBUG == False): - os.mknod(args.chroot_directory + node, mode, major, minor) + os.mknod(args.chroot_directory + node, mode, device) -# TODO: documentation +# :cp +# Copy a file from outside the chroot to inside the chroot, keeping the same +# (relative) location. def chroot_cp (line: str): print(f"shutil.copy({line}, {args.chroot_directory + line})") if (CHROOT_DEBUG == False): - shutil.copy(source, args.chroot_directory + source) + shutil.copy(line, args.chroot_directory + line) -# TODO: documentation -def chroot_cp_dir ( source: str ): - print("cp -R $1/* $CHROOT_DIR$1/.") - # TODO: Why mkdir before checking debug? - chroot_mkdir(source) +# :cp_dir +# Copy a directory from outside the chroot to inside the chroot, keeping the +# same (relative) location. +def chroot_cp_dir (line: str): + print(f"shutil.copytree({line}, {args.chroot_directory + line})") if (CHROOT_DEBUG == False): - shutil.copytree(source, args.chroot_directory + source) - - + # In Python v3.8+, shutil.copytree has a dirs_exist_ok keyword argument that + # prevents a FileExistsError when the destination directory exists. + # Unfortunately we are currently on v3.6.12, so we have to delete any + # directory that exists at that location. + if os.path.exists(args.chroot_directory + line): + shutil.rmtree(args.chroot_directory + line) + shutil.copytree(line, args.chroot_directory + line) + +# :chmod +# Change the permissions on a file in the chroot. def chroot_chmod (line: str): chmod_command = line.split() assert len(chmod_command) == 2, "chmod command expects 2 arguments!" @@ -146,33 +163,36 @@ def chroot_chmod (line: str): if (CHROOT_DEBUG == False): os.chmod(chmod_file, mode) +# :chmod_dir +# Change the permissions on a directory and everything inside it in the chroot. def chroot_chmod_dir (line: str): chmod_command = line.split() assert len(chmod_command) == 2, "chmod command expects 2 arguments!" mode = int(chmod_command[0], 8) - chmod_file = args.chroot_directory + chmod_command[1] - for root, dirs, files in os.walk(args.chroot_directory + chmod_file): + chmod_dir = args.chroot_directory + chmod_command[1] + for root, dirs, files in os.walk(args.chroot_directory + chmod_dir): for dir in dirs: print(f'os.chmod({os.path.join(root, dir)}, {int(mode, 8)})') if (CHROOT_DEBUG == FALSE): os.chmod(os.path.join(root, dir), int(mode, 8)) for file in files: - print(f'os.chmod({os.path.join(root, chmod_file)}, {int(mode, 8)})') + print(f'os.chmod({os.path.join(root, file)}, {int(mode, 8)})') if (CHROOT_DEBUG == FALSE): - os.chmod(os.path.join(root, chmod_file), int(mode, 8)) + os.chmod(os.path.join(root, file), int(mode, 8)) # :chown +# Change ownership of a file in the chroot def chroot_chown (line: str): - # TODO: change chown_command = line.split() assert len(chown_command) == 2, ":chown command expect 2 arguments!" user = chown_command[0] chown_file = args.chroot_directory + chown_command[1] - printf(f"os.chown({chown_file}, {user})") + printf(f"os.chown({args.chroot_directory + chown_file}, {user})") if (CHROOT_DEBUG == False): - os.chown(args.chroot_directory + file, user) + os.chown(args.chroot_directory + chown_file, user) # :chown_dir +# Change ownership of a directory and everything inside it in the chroot. def chroot_chown_dir (line: str): chown_command = line.split() assert len(chown_command) == 2, ":chown_dir command expect 2 arguments!" @@ -227,6 +247,7 @@ def chroot_setup (chroot_lst): if action is not None: action(line) +# Mapping the .lst action keys to the functions that run on their values action_dictionary = { ':file' : chroot_setup, ':mkdir' : chroot_mkdir, # done @@ -244,7 +265,8 @@ action_dictionary = { ':sh' : chroot_sh # done } -# TODO: documentation +# Run an initial check on the environment, ensuring that we are running on IBM i +# and setting environment variables def initial_check(): if (os.uname().sysname == 'OS400'): # CHROOT_DEBUG = False @@ -268,6 +290,7 @@ def initial_check(): # exit -1 +# Install any yum packages passed with the -i flag def yum_install(package_list: list): os.environ["LIBPATH"] = '/QOpenSys/pkgs/lib:/QOpenSys/usr/lib' install_template = Template('/QOpenSys/pkgs/bin/yum $yes --installroot=$chroot_dir install $package') @@ -291,8 +314,6 @@ if __name__ == '__main__': print(SCRIPT_DIR) auto_yes = args.auto_yes - - initial_check() # This is done because the arg may be a relative path name. @@ -316,12 +337,10 @@ if __name__ == '__main__': CHROOT_DIR = TEMP_DIR - if not os.path.isdir(CHROOT_DIR): print(CHROOT_DIR + " does not exist.") logging.debug(f"Creating directory at {CHROOT_DIR}") os.mkdir(CHROOT_DIR) - # TODO: Check creation else: if not auto_yes: print(CHROOT_DIR + " directory already exists") @@ -331,7 +350,6 @@ if __name__ == '__main__': sys.exit(-4) - ## CHANGE # Validate CHROOT TYPE Argument(s) if not args.chroot_type: # Only chroot_directory was provided to the script: diff --git a/config/chroot_includes.lst b/config/chroot_includes.lst index 4798366..cee412a 100644 --- a/config/chroot_includes.lst +++ b/config/chroot_includes.lst @@ -13,4 +13,3 @@ # :cp_dir /QOpenSys/usr/include - diff --git a/config/chroot_minimal.lst b/config/chroot_minimal.lst index adc9681..3d1887d 100644 --- a/config/chroot_minimal.lst +++ b/config/chroot_minimal.lst @@ -352,7 +352,7 @@ /QOpenSys/usr/lib/libld.a /QOpenSys/usr/lib/libm.a /QOpenSys/usr/lib/libnsl.a -/QOpenSys/usr/lib/libpmapi.a +# /QOpenSys/usr/lib/libpmapi.a /QOpenSys/usr/lib/libpthdebug.a /QOpenSys/usr/lib/libpthreads.a /QOpenSys/usr/lib/libpthreads_compat.a @@ -472,35 +472,35 @@ /QOpenSys/usr/bin /QOpenSys/bin /QOpenSys/usr/lib /QOpenSys/lib # alias -/QOpenSys/usr/bin/alias /QOpenSys/usr/bin/ -/QOpenSys/usr/bin/alias /QOpenSys/usr/bin/bg -/QOpenSys/usr/bin/alias /QOpenSys/usr/bin/cd -/QOpenSys/usr/bin/alias /QOpenSys/usr/bin/command -/QOpenSys/usr/bin/alias /QOpenSys/usr/bin/fc -/QOpenSys/usr/bin/alias /QOpenSys/usr/bin/fg -/QOpenSys/usr/bin/alias /QOpenSys/usr/bin/getopts -/QOpenSys/usr/bin/alias /QOpenSys/usr/bin/hash -/QOpenSys/usr/bin/alias /QOpenSys/usr/bin/jobs -/QOpenSys/usr/bin/alias /QOpenSys/usr/bin/read -/QOpenSys/usr/bin/alias /QOpenSys/usr/bin/type -/QOpenSys/usr/bin/alias /QOpenSys/usr/bin/ulimit -/QOpenSys/usr/bin/alias /QOpenSys/usr/bin/umask -/QOpenSys/usr/bin/alias /QOpenSys/usr/bin/unalias -/QOpenSys/usr/bin/alias /QOpenSys/usr/bin/wait +# /QOpenSys/usr/bin/alias /QOpenSys/usr/bin/ +# /QOpenSys/usr/bin/alias /QOpenSys/usr/bin/bg +# /QOpenSys/usr/bin/alias /QOpenSys/usr/bin/cd +# /QOpenSys/usr/bin/alias /QOpenSys/usr/bin/command +# /QOpenSys/usr/bin/alias /QOpenSys/usr/bin/fc +# /QOpenSys/usr/bin/alias /QOpenSys/usr/bin/fg +# /QOpenSys/usr/bin/alias /QOpenSys/usr/bin/getopts +# /QOpenSys/usr/bin/alias /QOpenSys/usr/bin/hash +# /QOpenSys/usr/bin/alias /QOpenSys/usr/bin/jobs +# /QOpenSys/usr/bin/alias /QOpenSys/usr/bin/read +# /QOpenSys/usr/bin/alias /QOpenSys/usr/bin/type +# /QOpenSys/usr/bin/alias /QOpenSys/usr/bin/ulimit +# /QOpenSys/usr/bin/alias /QOpenSys/usr/bin/umask +# /QOpenSys/usr/bin/alias /QOpenSys/usr/bin/unalias +# /QOpenSys/usr/bin/alias /QOpenSys/usr/bin/wait /QOpenSys/usr/bin/ksh /QOpenSys/usr/bin/sh /QOpenSys/usr/bin/rm /QOpenSys/usr/bin/rmdir # sbin to bin /QOpenSys/usr/sbin/chroot /QOpenSys/usr/bin/chroot /QOpenSys/usr/sbin/dump /QOpenSys/usr/bin/dump /QOpenSys/usr/sbin/trace /QOpenSys/usr/bin/trace -/QOpenSys/usr/sbin/trcoff /QOpenSys/usr/bin/trace -/QOpenSys/usr/sbin/trcon /QOpenSys/usr/bin/trace -/QOpenSys/usr/sbin/trcstop /QOpenSys/usr/bin/trace +# /QOpenSys/usr/sbin/trcoff /QOpenSys/usr/bin/trace +# /QOpenSys/usr/sbin/trcon /QOpenSys/usr/bin/trace +# /QOpenSys/usr/sbin/trcstop /QOpenSys/usr/bin/trace # individual libs /QOpenSys/usr/lib/libC128.a /QOpenSys/usr/lib/libC128_r.a /QOpenSys/usr/lib/libC.a /QOpenSys/usr/lib/libC_r.a /QOpenSys/usr/lib/libbsd.a /QOpenSys/usr/lib/libbsd_r.a -/QOpenSys/usr/lib/libc128.a /QOpenSys/usr/lib/libc_r.a +# /QOpenSys/usr/lib/libc128.a /QOpenSys/usr/lib/libc_r.a /QOpenSys/usr/lib/libc.a /QOpenSys/usr/lib/libc_r.a /QOpenSys/usr/lib/libc.a /QOpenSys/usr/lib/libc_t.a /QOpenSys/usr/lib/libxcurses.a /QOpenSys/usr/lib/libcurses.a @@ -563,7 +563,7 @@ /QOpenSys/usr/lib/libpthdebug.a /QOpenSys/usr/ccs/lib/libpthdebug.a /QOpenSys/usr/lib/libpthread.a /QOpenSys/usr/ccs/lib/libpthread.a /QOpenSys/usr/lib/libpthreads.a /QOpenSys/usr/ccs/lib/libpthreads.a -/QOpenSys/usr/lib/libpthreads_compat.a /QOpenSys/usr/ccs/lib/libpthreads_compat.a +/QOpenSys/usr/lib/libpthreads_compat.a /QOpenSys/usr/ccs/lib/bpthreads_compat.a /QOpenSys/usr/lib/librtl.a /QOpenSys/usr/ccs/lib/librtl.a /QOpenSys/usr/lib/libthread.a /QOpenSys/usr/ccs/lib/libthread.a /QOpenSys/usr/lib/libxcurses.a /QOpenSys/usr/ccs/lib/libxcurses.a @@ -611,12 +611,10 @@ # # run system command -# (system "CHGAUT OBJ('/QOpenSys/ranger/home/ranger') USER(RANGER) DTAAUT(*RWX) OBJAUT(*ALL) SUBTREE(*ALL)") +# (system "CHGAUT OBJ('/QOpenSys/ranger/home/ranger') USER(RANGER) DTAAUTRWX) # OBJAUT(*ALL) SUBTREE(*ALL)") # -- variable substitution example (mydir and myuser) -- -# > ./chroot_setup.sh chroot_system.lst /QOpenSys/ranger mydir=/QOpenSys/ranger myuser=RANGER +# > ./chroot_setup.sh chroot_system.lst /QOpenSys/ranger mydir=/QOpenSys/nger # myuser=RANGER # :system -# CHGAUT OBJ('/QOpenSys/ranger/home/ranger') USER(RANGER) DTAAUT(*RWX) OBJAUT(*ALL) SUBTREE(*ALL) -# CHGAUT OBJ('mydir/home/myuser') USER(myuser) DTAAUT(*RWX) OBJAUT(*ALL) SUBTREE(*ALL) - - +# CHGAUT OBJ('/QOpenSys/ranger/home/ranger') USER(RANGER) DTAAUT(*RWX) JAUT# (*ALL) SUBTREE(*ALL) +# CHGAUT OBJ('mydir/home/myuser') USER(myuser) DTAAUT(*RWX) OBJAUT(*ALL) SUBTREE# (*ALL) From db5ebad210b85ae9fcfc040fd0efe0e9bb8386b8 Mon Sep 17 00:00:00 2001 From: Mark Irish Date: Tue, 22 Dec 2020 12:05:41 -0600 Subject: [PATCH 04/31] Delete nodes before creating to keep up with #72 Signed-off-by: Mark Irish --- chroot_setup | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/chroot_setup b/chroot_setup index b704305..eb66960 100644 --- a/chroot_setup +++ b/chroot_setup @@ -68,7 +68,7 @@ def chroot_ln (line: str): # exists outside of the chroot. def chroot_ln_rel (line: str): ln_command = line.split() - assert len(mknod_command) == 1, ":ln_fix_rel action expects 1 argument!" + assert len(ln_command) == 1, ":ln_fix_rel action expects 1 argument!" directory = os.path.dirname(line) basename = os.path.basename(line) target = os.readlink(line) @@ -86,7 +86,7 @@ def chroot_ln_rel (line: str): # in, or simply create a relative symlink where one didn't exist before def chroot_ln_fix_rel (line: str): ln_command = line.split() - assert len(mknod_command) == 2, ":ln_fix_rel action expects 2 arguments!" + assert len(ln_command) == 2, ":ln_fix_rel action expects 2 arguments!" target = ln_command[1] link_name = ln_command[2] directory = os.path.dirname(link_name) @@ -126,8 +126,10 @@ def chroot_mknod (line: str): minor = mknod_command[3] device = os.makedev(int(major), int(minor)) + print(f"os.remove({args.chroot_directory + node})") print(f"os.mknod({args.chroot_directory + node}, {mode}, {device})") if (CHROOT_DEBUG == False): + os.remove(args.chroot_directory + node) os.mknod(args.chroot_directory + node, mode, device) # :cp From 10a759734a0375c76567d7a27cc2c1fc62197c87 Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Thu, 14 Jan 2021 11:11:46 -0600 Subject: [PATCH 05/31] refactor: Move arg parsing into __main__ code block --- chroot_setup | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/chroot_setup b/chroot_setup index eb66960..a947754 100644 --- a/chroot_setup +++ b/chroot_setup @@ -9,18 +9,6 @@ import stat from string import Template from enum import Enum -parser = argparse.ArgumentParser() -# positional arguments -parser.add_argument("chroot_directory", metavar="CHROOT_DIRECTORY", help="The location of the chroot to be created") -parser.add_argument("chroot_type", metavar="CHROOT_TYPE", help="A list of .lst files to use for generating the chroot", nargs="?") -# optional arguments -parser.add_argument("-g", dest='globals', nargs='*', metavar="", help="Environment variables to set when creating the chroot") -parser.add_argument("-i", dest='yum_installs', nargs='*', metavar="", help="A list of packages for yum to install in the chroot") -parser.add_argument("-y", dest='auto_yes', action='store_true', help="Automatically answer yes to input prompts") -parser.add_argument("-v", dest='verbose', action='store_true', help="Print verbose output when running") -args = parser.parse_args() -parser.parse_args() - print(""" ##### # # ###### ####### ####### ####### # # # # # # # # # # # @@ -306,6 +294,18 @@ def yum_install(package_list: list): # MAIN # if __name__ == '__main__': + parser = argparse.ArgumentParser() + # positional arguments + parser.add_argument("chroot_directory", metavar="CHROOT_DIRECTORY", help="The location of the chroot to be created") + parser.add_argument("chroot_type", metavar="CHROOT_TYPE", help="A list of .lst files to use for generating the chroot", nargs="?") + # optional arguments + parser.add_argument("-g", dest='globals', nargs='*', metavar="", help="Environment variables to set when creating the chroot") + parser.add_argument("-i", dest='yum_installs', nargs='*', metavar="", help="A list of packages for yum to install in the chroot") + parser.add_argument("-y", dest='auto_yes', action='store_true', help="Automatically answer yes to input prompts") + parser.add_argument("-v", dest='verbose', action='store_true', help="Print verbose output when running") + args = parser.parse_args() + parser.parse_args() + lst = 0 ops = 0 qsys = 0 From 4cd022aeeeb7a9bbf59e03d42a5eda1239bfd813 Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Thu, 14 Jan 2021 11:54:13 -0600 Subject: [PATCH 06/31] fixup! refactor: Move arg parsing into __main__ code block --- chroot_setup | 2 -- 1 file changed, 2 deletions(-) diff --git a/chroot_setup b/chroot_setup index a947754..9a3569e 100644 --- a/chroot_setup +++ b/chroot_setup @@ -29,8 +29,6 @@ print(""" CHROOT_DEBUG : bool = False -print(args.chroot_directory) - # :mkdir # Make a directory inside the chroot, as well as all intermediary directories def chroot_mkdir (dir: str): From 177c0a58c5f27478a547732d683d5a203b3ada97 Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Tue, 26 Jan 2021 16:18:34 -0600 Subject: [PATCH 07/31] fixup! Use 'not' in CHROOT_DEBUG conditionals --- chroot_setup | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/chroot_setup b/chroot_setup index 9a3569e..8d54dff 100644 --- a/chroot_setup +++ b/chroot_setup @@ -33,7 +33,7 @@ CHROOT_DEBUG : bool = False # Make a directory inside the chroot, as well as all intermediary directories def chroot_mkdir (dir: str): print(f'os.makedirs({args.chroot_directory + dir}, exist_ok=True)') - if (CHROOT_DEBUG == False): + if not CHROOT_DEBUG: os.makedirs(args.chroot_directory + dir, exist_ok=True) # :ln @@ -46,7 +46,7 @@ def chroot_ln (line: str): target = ln_command[0] link_name = ln_command[1] print(f'os.symlink({target}, {args.chroot_directory + link_name})') - if (CHROOT_DEBUG == False): + if not CHROOT_DEBUG: os.symlink(target, args.chroot_directory + link_name) # :ln_rel @@ -61,7 +61,7 @@ def chroot_ln_rel (line: str): here = os.getcwd() print(f'os.chdir({args.chroot_directory + directory})') print(f'os.symlink({target}, {basename})') - if (CHROOT_DEBUG == False): + if not CHROOT_DEBUG: os.chdir(args.chroot_directory + mydir) os.symlink(target, basename) os.chdir(here) @@ -81,7 +81,7 @@ def chroot_ln_fix_rel (line: str): print(f'os.chdir({args.chroot_directory + directory})') print(f'os.symlink{target}, {basename})') print(f'os.chdir({here})') - if (CHROOT_DEBUG == False): + if not CHROOT_DEBUG: os.chdir(args.chroot_directory + mydir) os.symlink(target, basename) os.chdir(here) @@ -114,7 +114,7 @@ def chroot_mknod (line: str): print(f"os.remove({args.chroot_directory + node})") print(f"os.mknod({args.chroot_directory + node}, {mode}, {device})") - if (CHROOT_DEBUG == False): + if not CHROOT_DEBUG: os.remove(args.chroot_directory + node) os.mknod(args.chroot_directory + node, mode, device) @@ -123,7 +123,7 @@ def chroot_mknod (line: str): # (relative) location. def chroot_cp (line: str): print(f"shutil.copy({line}, {args.chroot_directory + line})") - if (CHROOT_DEBUG == False): + if not CHROOT_DEBUG: shutil.copy(line, args.chroot_directory + line) # :cp_dir @@ -131,7 +131,7 @@ def chroot_cp (line: str): # same (relative) location. def chroot_cp_dir (line: str): print(f"shutil.copytree({line}, {args.chroot_directory + line})") - if (CHROOT_DEBUG == False): + if not CHROOT_DEBUG: # In Python v3.8+, shutil.copytree has a dirs_exist_ok keyword argument that # prevents a FileExistsError when the destination directory exists. # Unfortunately we are currently on v3.6.12, so we have to delete any @@ -148,7 +148,7 @@ def chroot_chmod (line: str): mode = int(chmod_command[0], 8) chmod_file = args.chroot_directory + chmod_command[1] printf(f"os.chmod({chmod_file}, {mode})") - if (CHROOT_DEBUG == False): + if not CHROOT_DEBUG: os.chmod(chmod_file, mode) # :chmod_dir @@ -161,11 +161,11 @@ def chroot_chmod_dir (line: str): for root, dirs, files in os.walk(args.chroot_directory + chmod_dir): for dir in dirs: print(f'os.chmod({os.path.join(root, dir)}, {int(mode, 8)})') - if (CHROOT_DEBUG == FALSE): + if not CHROOT_DEBUG: os.chmod(os.path.join(root, dir), int(mode, 8)) for file in files: print(f'os.chmod({os.path.join(root, file)}, {int(mode, 8)})') - if (CHROOT_DEBUG == FALSE): + if not CHROOT_DEBUG: os.chmod(os.path.join(root, file), int(mode, 8)) # :chown @@ -176,7 +176,7 @@ def chroot_chown (line: str): user = chown_command[0] chown_file = args.chroot_directory + chown_command[1] printf(f"os.chown({args.chroot_directory + chown_file}, {user})") - if (CHROOT_DEBUG == False): + if not CHROOT_DEBUG: os.chown(args.chroot_directory + chown_file, user) # :chown_dir @@ -189,11 +189,11 @@ def chroot_chown_dir (line: str): for root, dirs, files in os.walk(args.chroot_directory + chown_directory): for dir in dirs: printf(f'os.chown({os.path.join(root, dir)}, {user})') - if (CHROOT_DEBUG == False): + if not CHROOT_DEBUG: os.chown(os.path.join(root, dir), user) for file in files: printf(f'os.chown({os.path.join(root, file)}, {user})') - if (CHROOT_DEBUG == False): + if not CHROOT_DEBUG: os.chown(os.path.join(root, file), user) # :system @@ -201,7 +201,7 @@ def chroot_chown_dir (line: str): def chroot_system(line: str): line = line.rstrip() print('system -i "' + line + '"') - if (CHROOT_DEBUG == False): + if not CHROOT_DEBUG: os.system('system -i "' + line + '"') # :sh @@ -209,7 +209,7 @@ def chroot_system(line: str): # run "by calling the Standard C function system()." def chroot_sh(line: str): print(line) - if (CHROOT_DEBUG == False): + if not CHROOT_DEBUG: os.system(line) # :file From e0a773d3b7f550c836f472cf4e3760a6339dc11d Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Tue, 26 Jan 2021 19:27:37 -0600 Subject: [PATCH 08/31] fixup! Use f-strings instead of concat --- chroot_setup | 102 +++++++++++++++++++++++++-------------------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/chroot_setup b/chroot_setup index 8d54dff..80c42f9 100644 --- a/chroot_setup +++ b/chroot_setup @@ -32,9 +32,9 @@ CHROOT_DEBUG : bool = False # :mkdir # Make a directory inside the chroot, as well as all intermediary directories def chroot_mkdir (dir: str): - print(f'os.makedirs({args.chroot_directory + dir}, exist_ok=True)') + print(f"os.makedirs({args.chroot_directory}{dir}, exist_ok=True)") if not CHROOT_DEBUG: - os.makedirs(args.chroot_directory + dir, exist_ok=True) + os.makedirs(f"{args.chroot_directory}{dir}", exist_ok=True) # :ln # Create an absolute symlink. We don't have to go inside the chroot, since the @@ -45,9 +45,9 @@ def chroot_ln (line: str): assert len(ln_command) == 2, ":ln action expects 2 arguments!" target = ln_command[0] link_name = ln_command[1] - print(f'os.symlink({target}, {args.chroot_directory + link_name})') + print(f"os.symlink({target}, {args.chroot_directory}{link_name})") if not CHROOT_DEBUG: - os.symlink(target, args.chroot_directory + link_name) + os.symlink(target, f"{args.chroot_directory}{link_name}") # :ln_rel # Create a relative symlink in the chroot that mirrors a relative symlink that @@ -59,10 +59,10 @@ def chroot_ln_rel (line: str): basename = os.path.basename(line) target = os.readlink(line) here = os.getcwd() - print(f'os.chdir({args.chroot_directory + directory})') - print(f'os.symlink({target}, {basename})') + print(f"os.chdir({args.chroot_directory}{directory})") + print(f"os.symlink({target}, {basename})") if not CHROOT_DEBUG: - os.chdir(args.chroot_directory + mydir) + os.chdir(f"{args.chroot_directory}{mydir}") os.symlink(target, basename) os.chdir(here) @@ -78,11 +78,11 @@ def chroot_ln_fix_rel (line: str): directory = os.path.dirname(link_name) basename = os.path.basename(link_name) here = os.getcwd() - print(f'os.chdir({args.chroot_directory + directory})') - print(f'os.symlink{target}, {basename})') - print(f'os.chdir({here})') + print(f"os.chdir({args.chroot_directory}{directory})") + print(f"os.symlink{target}, {basename})") + print(f"os.chdir({here})") if not CHROOT_DEBUG: - os.chdir(args.chroot_directory + mydir) + os.chdir(f"{args.chroot_directory}{mydir}") os.symlink(target, basename) os.chdir(here) @@ -112,33 +112,33 @@ def chroot_mknod (line: str): minor = mknod_command[3] device = os.makedev(int(major), int(minor)) - print(f"os.remove({args.chroot_directory + node})") - print(f"os.mknod({args.chroot_directory + node}, {mode}, {device})") + print(f"os.remove({args.chroot_directory}{node})") + print(f"os.mknod({args.chroot_directory}{node}, {mode}, {device})") if not CHROOT_DEBUG: - os.remove(args.chroot_directory + node) - os.mknod(args.chroot_directory + node, mode, device) + os.remove(f"{args.chroot_directory}{node}") + os.mknod(f"{args.chroot_directory}{node}", mode, device) # :cp # Copy a file from outside the chroot to inside the chroot, keeping the same # (relative) location. def chroot_cp (line: str): - print(f"shutil.copy({line}, {args.chroot_directory + line})") + print(f"shutil.copy({line}, {args.chroot_directory}{line})") if not CHROOT_DEBUG: - shutil.copy(line, args.chroot_directory + line) + shutil.copy(line, f"{args.chroot_directory}{line}") # :cp_dir # Copy a directory from outside the chroot to inside the chroot, keeping the # same (relative) location. def chroot_cp_dir (line: str): - print(f"shutil.copytree({line}, {args.chroot_directory + line})") + print(f"shutil.copytree({line}, {args.chroot_directory}{line})") if not CHROOT_DEBUG: # In Python v3.8+, shutil.copytree has a dirs_exist_ok keyword argument that # prevents a FileExistsError when the destination directory exists. # Unfortunately we are currently on v3.6.12, so we have to delete any # directory that exists at that location. - if os.path.exists(args.chroot_directory + line): - shutil.rmtree(args.chroot_directory + line) - shutil.copytree(line, args.chroot_directory + line) + if os.path.exists(f"{args.chroot_directory}{line}"): + shutil.rmtree(f"{args.chroot_directory}{line}") + shutil.copytree(line, f"{args.chroot_directory}{line}") # :chmod # Change the permissions on a file in the chroot. @@ -146,7 +146,7 @@ def chroot_chmod (line: str): chmod_command = line.split() assert len(chmod_command) == 2, "chmod command expects 2 arguments!" mode = int(chmod_command[0], 8) - chmod_file = args.chroot_directory + chmod_command[1] + chmod_file = f"{args.chroot_directory}{chmod_command[1]}" printf(f"os.chmod({chmod_file}, {mode})") if not CHROOT_DEBUG: os.chmod(chmod_file, mode) @@ -157,14 +157,14 @@ def chroot_chmod_dir (line: str): chmod_command = line.split() assert len(chmod_command) == 2, "chmod command expects 2 arguments!" mode = int(chmod_command[0], 8) - chmod_dir = args.chroot_directory + chmod_command[1] - for root, dirs, files in os.walk(args.chroot_directory + chmod_dir): + chmod_dir = f"{args.chroot_directory}{chmod_command[1]}" + for root, dirs, files in os.walk(f"{args.chroot_directory}{chmod_dir}"): for dir in dirs: - print(f'os.chmod({os.path.join(root, dir)}, {int(mode, 8)})') + print(f"os.chmod({os.path.join(root, dir)}, {int(mode, 8)})") if not CHROOT_DEBUG: os.chmod(os.path.join(root, dir), int(mode, 8)) for file in files: - print(f'os.chmod({os.path.join(root, file)}, {int(mode, 8)})') + print(f"os.chmod({os.path.join(root, file)}, {int(mode, 8)})") if not CHROOT_DEBUG: os.chmod(os.path.join(root, file), int(mode, 8)) @@ -174,10 +174,10 @@ def chroot_chown (line: str): chown_command = line.split() assert len(chown_command) == 2, ":chown command expect 2 arguments!" user = chown_command[0] - chown_file = args.chroot_directory + chown_command[1] - printf(f"os.chown({args.chroot_directory + chown_file}, {user})") + chown_file = f"{args.chroot_directory}{chown_command[1]}" + printf(f"os.chown({args.chroot_directory}{chown_file}, {user})") if not CHROOT_DEBUG: - os.chown(args.chroot_directory + chown_file, user) + os.chown(f"{args.chroot_directory}{chown_file, user}") # :chown_dir # Change ownership of a directory and everything inside it in the chroot. @@ -185,14 +185,14 @@ def chroot_chown_dir (line: str): chown_command = line.split() assert len(chown_command) == 2, ":chown_dir command expect 2 arguments!" user = chown_command[0] - chown_directory = args.chroot_directory + chown_command[1] - for root, dirs, files in os.walk(args.chroot_directory + chown_directory): + chown_directory = f"{args.chroot_directory}{chown_command[1]}" + for root, dirs, files in os.walk(f"{args.chroot_directory}{chown_directory}"): for dir in dirs: - printf(f'os.chown({os.path.join(root, dir)}, {user})') + printf(f"os.chown({os.path.join(root, dir)}, {user})") if not CHROOT_DEBUG: os.chown(os.path.join(root, dir), user) for file in files: - printf(f'os.chown({os.path.join(root, file)}, {user})') + printf(f"os.chown({os.path.join(root, file)}, {user})") if not CHROOT_DEBUG: os.chown(os.path.join(root, file), user) @@ -200,9 +200,9 @@ def chroot_chown_dir (line: str): # Executes a line from a .lst file using the /QOpenSys/usr/bin/system utility def chroot_system(line: str): line = line.rstrip() - print('system -i "' + line + '"') + print(f"system -i {line}") if not CHROOT_DEBUG: - os.system('system -i "' + line + '"') + os.system(f"system -i {line}") # :sh # Executes a line from a .lst file using Pythons os.system function, which is @@ -267,8 +267,8 @@ def initial_check(): print("**********************") if (args.verbose): - print('PATH=' + PATH) - print('LIBPATH=' + LIBPATH) + print(f"PATH={PATH}") + print(f"LIBPATH={LIBPATH}") else: # CHROOT_DEBUG = True @@ -309,7 +309,7 @@ if __name__ == '__main__': qsys = 0 CHROOT_DIR = "" CHROOT_LIST = "" - SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__)) + "/config" + SCRIPT_DIR = f"{os.path.dirname(os.path.realpath(__file__))}/config" print(SCRIPT_DIR) @@ -326,9 +326,9 @@ if __name__ == '__main__': if (args.verbose): logging.basicConfig(level=logging.DEBUG) - logging.debug("Script directory: " + SCRIPT_DIR) + logging.debug(f"Script directory: {SCRIPT_DIR}") os.chdir(SCRIPT_DIR) - logging.debug("PWD: " + os.getcwd()) + logging.debug(f"PWD: {os.getcwd()}") if not TEMP_DIR.startswith('/QOpenSys/'): print("\nERROR: [CHROOT DIRECTORY] Must begin with /QOpenSys/...\n") @@ -338,12 +338,12 @@ if __name__ == '__main__': CHROOT_DIR = TEMP_DIR if not os.path.isdir(CHROOT_DIR): - print(CHROOT_DIR + " does not exist.") + print(f"{CHROOT_DIR} does not exist.") logging.debug(f"Creating directory at {CHROOT_DIR}") os.mkdir(CHROOT_DIR) else: if not auto_yes: - print(CHROOT_DIR + " directory already exists") + print(f"{CHROOT_DIR} directory already exists") val = input("Would you like to continue chroot setup? [y/N]") if not val == "y": print("Bye") @@ -355,30 +355,30 @@ if __name__ == '__main__': # Only chroot_directory was provided to the script: # Ask if minimal with includes chroot is desired if not auto_yes: - val = input("Would you like to create a minimal chroot w/ includes @ " + CHROOT_DIR + "? [y/N]:") + val = input(f"Would you like to create a minimal chroot w/ includes @ {CHROOT_DIR}? [y/N]:") if not val == "y": print("Specify your desired [CHROOT TYPE]") parser.print_help sys.exit(-5) mylist = [] - mylist.append(SCRIPT_DIR + "/chroot_includes.lst") - mylist.append(SCRIPT_DIR + "/chroot_minimal.lst") + mylist.append(f"{SCRIPT_DIR}/chroot_includes.lst") + mylist.append(f"{SCRIPT_DIR}/chroot_minimal.lst") else: # If chroot types were specified, then use those for arg in args.chroot_type: - print("Chroot type is: " + arg) + print(f"Chroot type is: {arg}") CHROOT_LIST = arg # add chroot prefix if it doesn't exist if not CHROOT_LIST.startswith('chroot'): - CHROOT_LIST = 'chroot_' + CHROOT_LIST + CHROOT_LIST = f"chroot_{CHROOT_LIST}" # check that the .lst file name was given if not CHROOT_LIST.endswith('.lst'): - CHROOT_LIST = CHROOT_LIST + '.lst' + CHROOT_LIST = f"{CHROOT_LIST}.lst" # check that the .lst file exists if not os.path.isfile(CHROOT_LIST): @@ -401,7 +401,7 @@ if __name__ == '__main__': for chroot_file in mylist: print("=====================================") - print("setting up based on " + chroot_file) + print(f"setting up based on {chroot_file}") print("=====================================") for key in globals_dictionary: @@ -412,8 +412,8 @@ if __name__ == '__main__': for key in globals_dictionary: del os.environ[key] - os.makedirs(args.chroot_directory + '/QOpenSys/etc', exist_ok=True) - etc_profile = (args.chroot_directory + '/QOpenSys/etc/profile') + os.makedirs(f"{args.chroot_directory}/QOpenSys/etc", exist_ok=True) + etc_profile = (f"{args.chroot_directory}/QOpenSys/etc/profile") if not os.path.isfile(etc_profile): print('Priming /QOpenSys/etc/profile') etc_file = open(etc_profile, 'a') From 1c33b9710c4b9f620b8659690c32ab5acf6bb6f5 Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Tue, 26 Jan 2021 19:49:59 -0600 Subject: [PATCH 09/31] fixup! actions dictonary --- chroot_setup | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chroot_setup b/chroot_setup index 80c42f9..377b91c 100644 --- a/chroot_setup +++ b/chroot_setup @@ -228,7 +228,7 @@ def chroot_setup (chroot_lst): # Determine action elif line.startswith(':'): - action = action_dictionary[line] + action = actions.get(line, None) # Execute action else: @@ -236,7 +236,7 @@ def chroot_setup (chroot_lst): action(line) # Mapping the .lst action keys to the functions that run on their values -action_dictionary = { +actions = { ':file' : chroot_setup, ':mkdir' : chroot_mkdir, # done ':ln_fix_rel' : chroot_ln_fix_rel, # done From 7a5e93adb7b1ac5f3bee0756ca240518a945f4c0 Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Tue, 26 Jan 2021 20:16:02 -0600 Subject: [PATCH 10/31] fixup! No longer set LIBPATH --- chroot_setup | 4 ---- 1 file changed, 4 deletions(-) diff --git a/chroot_setup b/chroot_setup index 377b91c..66d393f 100644 --- a/chroot_setup +++ b/chroot_setup @@ -259,16 +259,13 @@ def initial_check(): if (os.uname().sysname == 'OS400'): # CHROOT_DEBUG = False PATH='/QOpenSys/pkgs/bin:/QOpenSys/pkgs/sbin:/QOpenSys/usr/bin:/QOpenSys/usr/sbin:' - LIBPATH='/QOpenSys/pkgs/lib:/QOpenSys/usr/lib' os.environ['PATH'] = PATH - os.environ['LIBPATH'] = LIBPATH print("**********************") print("Live IBM i session (changes made).") print("**********************") if (args.verbose): print(f"PATH={PATH}") - print(f"LIBPATH={LIBPATH}") else: # CHROOT_DEBUG = True @@ -280,7 +277,6 @@ def initial_check(): # Install any yum packages passed with the -i flag def yum_install(package_list: list): - os.environ["LIBPATH"] = '/QOpenSys/pkgs/lib:/QOpenSys/usr/lib' install_template = Template('/QOpenSys/pkgs/bin/yum $yes --installroot=$chroot_dir install $package') auto_yes = '-y' if args.auto_yes else '' for package in package_list: From e6ff3cfda15c3ceb37e83c23e1bbae7f0e9dbbe0 Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Tue, 26 Jan 2021 21:18:33 -0600 Subject: [PATCH 11/31] fixup! No longer set PATH --- chroot_setup | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/chroot_setup b/chroot_setup index 66d393f..497ed26 100644 --- a/chroot_setup +++ b/chroot_setup @@ -136,6 +136,7 @@ def chroot_cp_dir (line: str): # prevents a FileExistsError when the destination directory exists. # Unfortunately we are currently on v3.6.12, so we have to delete any # directory that exists at that location. + if os.path.exists(f"{args.chroot_directory}{line}"): shutil.rmtree(f"{args.chroot_directory}{line}") shutil.copytree(line, f"{args.chroot_directory}{line}") @@ -258,15 +259,10 @@ actions = { def initial_check(): if (os.uname().sysname == 'OS400'): # CHROOT_DEBUG = False - PATH='/QOpenSys/pkgs/bin:/QOpenSys/pkgs/sbin:/QOpenSys/usr/bin:/QOpenSys/usr/sbin:' - os.environ['PATH'] = PATH print("**********************") print("Live IBM i session (changes made).") print("**********************") - if (args.verbose): - print(f"PATH={PATH}") - else: # CHROOT_DEBUG = True print("**********************") From 22b0b1d6b21bb138bf2b466d2b310d6ddb3e4062 Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Wed, 27 Jan 2021 08:42:54 -0600 Subject: [PATCH 12/31] fixup! check for python 3.8 to use dirs_exist with shutil.copytree --- chroot_setup | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/chroot_setup b/chroot_setup index 497ed26..f04e3a1 100644 --- a/chroot_setup +++ b/chroot_setup @@ -136,10 +136,12 @@ def chroot_cp_dir (line: str): # prevents a FileExistsError when the destination directory exists. # Unfortunately we are currently on v3.6.12, so we have to delete any # directory that exists at that location. - - if os.path.exists(f"{args.chroot_directory}{line}"): - shutil.rmtree(f"{args.chroot_directory}{line}") - shutil.copytree(line, f"{args.chroot_directory}{line}") + if sys.version_info >= (3,8): + shutil.copytree(line, f"{args.chroot_directory}{line}", dirs_exist=True) + else: + if os.path.exists(f"{args.chroot_directory}{line}"): + shutil.rmtree(f"{args.chroot_directory}{line}") + shutil.copytree(line, f"{args.chroot_directory}{line}") # :chmod # Change the permissions on a file in the chroot. From 04ca7a33a71c868370b6315b537307b3984e03c2 Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Wed, 27 Jan 2021 18:11:36 -0600 Subject: [PATCH 13/31] fixup! succinctly access ln_command elements --- chroot_setup | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/chroot_setup b/chroot_setup index f04e3a1..eeab1e7 100644 --- a/chroot_setup +++ b/chroot_setup @@ -73,8 +73,7 @@ def chroot_ln_rel (line: str): def chroot_ln_fix_rel (line: str): ln_command = line.split() assert len(ln_command) == 2, ":ln_fix_rel action expects 2 arguments!" - target = ln_command[1] - link_name = ln_command[2] + target, link_name = ln_command directory = os.path.dirname(link_name) basename = os.path.basename(link_name) here = os.getcwd() From 3464874400d88f3e5f5d4e55688999c1d3013fe5 Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Wed, 27 Jan 2021 18:58:29 -0600 Subject: [PATCH 14/31] fixup! create only character devices --- chroot_setup | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/chroot_setup b/chroot_setup index eeab1e7..0ca3aee 100644 --- a/chroot_setup +++ b/chroot_setup @@ -94,18 +94,13 @@ def chroot_mknod (line: str): assert len(mknod_command) == 4, "mknod command expects 4 arguments!" node: str = mknod_command[0] - # mode is created by OR-ing the permissions with the type of node to be - # created - if (mknod_command[1] == 'p'): - mode = 0o644 | stat.S_IFIFO - elif (mknod_command[1] == 'b'): - mode = 0o644 | stat.S_IFBLK - elif (mknod_command[1] == 'c'): - mode = 0o644 | stat.S_IFCHR - else: - print("Unrecognized mknod type; Valid types are 'p', 'b', and 'c'") + # we only support creating character special devices + if mknod_command[1] != 'c': + print("Unrecognized mknod type; Valid type is 'c'") sys.exit(-6) + mode = 0o644 | stat.S_IFCHR + # device major and minor numbers are created through os.makedev major = mknod_command[2] minor = mknod_command[3] From f8c5350b141afd53c324da0d4ccf2a3303661f08 Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Thu, 28 Jan 2021 11:48:42 -0600 Subject: [PATCH 15/31] fixup! Creating profile file --- chroot_setup | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/chroot_setup b/chroot_setup index 0ca3aee..af1ffb7 100644 --- a/chroot_setup +++ b/chroot_setup @@ -402,13 +402,15 @@ if __name__ == '__main__': os.makedirs(f"{args.chroot_directory}/QOpenSys/etc", exist_ok=True) etc_profile = (f"{args.chroot_directory}/QOpenSys/etc/profile") - if not os.path.isfile(etc_profile): - print('Priming /QOpenSys/etc/profile') - etc_file = open(etc_profile, 'a') - etc_file.write('PATH=/QOpenSys/pkgs/bin:$PATH\n') - etc_file.write('export PATH\n') - etc_file.write('OBJECT_MODE=64\n') - etc_file.write('export OBJECT_MODE\n') + try: + with open(etc_profile, 'x') as profile: + print('Priming /QOpenSys/etc/profile') + print('PATH=/QOpenSys/pkgs/bin:$PATH', file=profile) + print('export PATH', file=profile) + print('OBJECT_MODE=64', file=profile) + print('export OBJECT_MODE', file=profile) + except FileExistsError: + logging.debug(f"{etc_profile} already exists") # perform installs if set if args.yum_installs is not None: From 05412ed754a851641bbb33136bb66743ee0578a8 Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Thu, 28 Jan 2021 11:54:05 -0600 Subject: [PATCH 16/31] fixup! Remove unused variables --- chroot_setup | 3 --- 1 file changed, 3 deletions(-) diff --git a/chroot_setup b/chroot_setup index af1ffb7..7a3e781 100644 --- a/chroot_setup +++ b/chroot_setup @@ -292,9 +292,6 @@ if __name__ == '__main__': args = parser.parse_args() parser.parse_args() - lst = 0 - ops = 0 - qsys = 0 CHROOT_DIR = "" CHROOT_LIST = "" SCRIPT_DIR = f"{os.path.dirname(os.path.realpath(__file__))}/config" From 3814d9b3bdbeed89a75b6b18e95a4dfb989f3eb9 Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Thu, 28 Jan 2021 12:57:27 -0600 Subject: [PATCH 17/31] fixup! use subprocess instead of os.system --- chroot_setup | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/chroot_setup b/chroot_setup index 7a3e781..72ad9c2 100644 --- a/chroot_setup +++ b/chroot_setup @@ -6,6 +6,7 @@ import sys import shutil import logging import stat +import subprocess from string import Template from enum import Enum @@ -199,7 +200,7 @@ def chroot_system(line: str): line = line.rstrip() print(f"system -i {line}") if not CHROOT_DEBUG: - os.system(f"system -i {line}") + subprocess.run(['system', '-i', line], check=True) # :sh # Executes a line from a .lst file using Pythons os.system function, which is @@ -208,6 +209,7 @@ def chroot_sh(line: str): print(line) if not CHROOT_DEBUG: os.system(line) + subprocess.run(line.split(), check=True) # :file # Parses and executes additional .lst files @@ -269,12 +271,12 @@ def initial_check(): # Install any yum packages passed with the -i flag def yum_install(package_list: list): - install_template = Template('/QOpenSys/pkgs/bin/yum $yes --installroot=$chroot_dir install $package') + install_template = Template('/QOpenSys/pkgs/bin/yum $yes --installroot=$chroot_dir install $packages') auto_yes = '-y' if args.auto_yes else '' - for package in package_list: - command = install_template.substitute(yes=auto_yes, chroot_dir=args.chroot_directory, package=package) - logging.debug(command) - os.system(command) + packages = " ".join(package_list) + command = install_template.substitute(yes=auto_yes, chroot_dir=args.chroot_directory, packages=packages) + logging.debug(command) + subprocess.run(command.split(), check=True) # # MAIN From dd947c5853677968616277d9abdff9dc0c186730 Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Thu, 28 Jan 2021 13:13:07 -0600 Subject: [PATCH 18/31] fixup! exit if platfrom is not IBM i --- chroot_setup | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chroot_setup b/chroot_setup index 72ad9c2..c5b608a 100644 --- a/chroot_setup +++ b/chroot_setup @@ -266,7 +266,7 @@ def initial_check(): print("**********************") print("Not IBM i, no action is taken (debug flow purpose only).") print("**********************") - # exit -1 + sys.exit(-1) # Install any yum packages passed with the -i flag From b12fbbc0988ca11554f2192461ff414d83482286 Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Wed, 3 Feb 2021 16:19:28 -0600 Subject: [PATCH 19/31] fixup! Raise value errors instead of assert --- chroot_setup | 44 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/chroot_setup b/chroot_setup index c5b608a..70f8c88 100644 --- a/chroot_setup +++ b/chroot_setup @@ -43,9 +43,12 @@ def chroot_mkdir (dir: str): # Python won't check and therefore won't throw an error. def chroot_ln (line: str): ln_command = line.split() - assert len(ln_command) == 2, ":ln action expects 2 arguments!" - target = ln_command[0] - link_name = ln_command[1] + + if not len(ln_command) == 2: + raise ValueError(":ln action expects 2 arguments!") + + target, link_name = ln_command + print(f"os.symlink({target}, {args.chroot_directory}{link_name})") if not CHROOT_DEBUG: os.symlink(target, f"{args.chroot_directory}{link_name}") @@ -55,7 +58,10 @@ def chroot_ln (line: str): # exists outside of the chroot. def chroot_ln_rel (line: str): ln_command = line.split() - assert len(ln_command) == 1, ":ln_fix_rel action expects 1 argument!" + + if not len(ln_command) == 1: + raise ValueError(":ln_rel action expects 1 argument!") + directory = os.path.dirname(line) basename = os.path.basename(line) target = os.readlink(line) @@ -73,7 +79,10 @@ def chroot_ln_rel (line: str): # in, or simply create a relative symlink where one didn't exist before def chroot_ln_fix_rel (line: str): ln_command = line.split() - assert len(ln_command) == 2, ":ln_fix_rel action expects 2 arguments!" + + if not len(ln_command) == 2: + raise ValueError(":ln_fix_rel action expects 2 arguments!") + target, link_name = ln_command directory = os.path.dirname(link_name) basename = os.path.basename(link_name) @@ -92,7 +101,10 @@ def chroot_mknod (line: str): # We are passed a mknod terminal commmand. Need to parse it to make it work # with os.mknod. mknod_command = line.split() - assert len(mknod_command) == 4, "mknod command expects 4 arguments!" + + if not len(mknod_command) == 4: + raise ValueError(":mknod action expects 4 arguments!") + node: str = mknod_command[0] # we only support creating character special devices @@ -142,7 +154,10 @@ def chroot_cp_dir (line: str): # Change the permissions on a file in the chroot. def chroot_chmod (line: str): chmod_command = line.split() - assert len(chmod_command) == 2, "chmod command expects 2 arguments!" + + if not len(chmod_command) == 2: + raise ValueError(":chmod action expects 2 arguments!") + mode = int(chmod_command[0], 8) chmod_file = f"{args.chroot_directory}{chmod_command[1]}" printf(f"os.chmod({chmod_file}, {mode})") @@ -153,7 +168,10 @@ def chroot_chmod (line: str): # Change the permissions on a directory and everything inside it in the chroot. def chroot_chmod_dir (line: str): chmod_command = line.split() - assert len(chmod_command) == 2, "chmod command expects 2 arguments!" + + if not len(chmod_command) == 2: + raise ValueError(":chmod_dir action expects 2 arguments!") + mode = int(chmod_command[0], 8) chmod_dir = f"{args.chroot_directory}{chmod_command[1]}" for root, dirs, files in os.walk(f"{args.chroot_directory}{chmod_dir}"): @@ -170,7 +188,10 @@ def chroot_chmod_dir (line: str): # Change ownership of a file in the chroot def chroot_chown (line: str): chown_command = line.split() - assert len(chown_command) == 2, ":chown command expect 2 arguments!" + + if not len(chown_command) == 2: + raise ValueError(":chown action expect 2 arguments!") + user = chown_command[0] chown_file = f"{args.chroot_directory}{chown_command[1]}" printf(f"os.chown({args.chroot_directory}{chown_file}, {user})") @@ -181,7 +202,10 @@ def chroot_chown (line: str): # Change ownership of a directory and everything inside it in the chroot. def chroot_chown_dir (line: str): chown_command = line.split() - assert len(chown_command) == 2, ":chown_dir command expect 2 arguments!" + + if not len(chown_command) == 2: + raise ValueError(":chown_dir action expect 2 arguments!") + user = chown_command[0] chown_directory = f"{args.chroot_directory}{chown_command[1]}" for root, dirs, files in os.walk(f"{args.chroot_directory}{chown_directory}"): From d80220a4021beea64de397f6049d11c4f76db3e7 Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Mon, 8 Feb 2021 15:12:46 -0600 Subject: [PATCH 20/31] fixup! TOCTOU race condition - add input_yes function - Use * for chroot_type nargs --- chroot_setup | 82 +++++++++++++++++++++++++++------------------------- 1 file changed, 43 insertions(+), 39 deletions(-) diff --git a/chroot_setup b/chroot_setup index 70f8c88..cd6e322 100644 --- a/chroot_setup +++ b/chroot_setup @@ -238,25 +238,24 @@ def chroot_sh(line: str): # :file # Parses and executes additional .lst files def chroot_setup (chroot_lst): - lst_file = open(chroot_lst, 'r') - action = None + with open(chroot_lst, 'r') as lst_file: + action = None + # Iterate over all lines in the file, executing actions where encountered + for line in lst_file: + line = line.strip() - # Iterate over all lines in the file, executing actions where encountered - for line in lst_file: - line = line.strip() + # Skip blank lines and comments + if not line or line.startswith('#'): + continue - # Skip blank lines and comments - if not line or line.startswith('#'): - continue + # Determine action + elif line.startswith(':'): + action = actions.get(line, None) - # Determine action - elif line.startswith(':'): - action = actions.get(line, None) - - # Execute action - else: - if action is not None: - action(line) + # Execute action + else: + if action is not None: + action(line) # Mapping the .lst action keys to the functions that run on their values actions = { @@ -302,6 +301,9 @@ def yum_install(package_list: list): logging.debug(command) subprocess.run(command.split(), check=True) +def input_yes(*args, **kwargs): + return 'y' + # # MAIN # @@ -309,7 +311,7 @@ if __name__ == '__main__': parser = argparse.ArgumentParser() # positional arguments parser.add_argument("chroot_directory", metavar="CHROOT_DIRECTORY", help="The location of the chroot to be created") - parser.add_argument("chroot_type", metavar="CHROOT_TYPE", help="A list of .lst files to use for generating the chroot", nargs="?") + parser.add_argument("chroot_type", metavar="CHROOT_TYPE", help="A list of .lst files to use for generating the chroot", nargs="*") # optional arguments parser.add_argument("-g", dest='globals', nargs='*', metavar="", help="Environment variables to set when creating the chroot") parser.add_argument("-i", dest='yum_installs', nargs='*', metavar="", help="A list of packages for yum to install in the chroot") @@ -353,26 +355,33 @@ if __name__ == '__main__': logging.debug(f"Creating directory at {CHROOT_DIR}") os.mkdir(CHROOT_DIR) else: - if not auto_yes: - print(f"{CHROOT_DIR} directory already exists") - val = input("Would you like to continue chroot setup? [y/N]") - if not val == "y": - print("Bye") - sys.exit(-4) + if args.auto_yes: + input = input_yes + + print(f"{CHROOT_DIR} directory already exists") + val = input("Would you like to continue chroot setup? [y/N]: ") + + if not val == "y": + print("Bye") + sys.exit(-4) # Validate CHROOT TYPE Argument(s) + mylist = [] + if not args.chroot_type: # Only chroot_directory was provided to the script: # Ask if minimal with includes chroot is desired - if not auto_yes: - val = input(f"Would you like to create a minimal chroot w/ includes @ {CHROOT_DIR}? [y/N]:") - if not val == "y": - print("Specify your desired [CHROOT TYPE]") - parser.print_help - sys.exit(-5) - - mylist = [] + + if args.auto_yes: + input = input_yes + + val = input(f"Would you like to create a minimal chroot w/ includes @ {CHROOT_DIR}? [y/N]: ") + if not val == "y": + print("Specify your desired [CHROOT TYPE]") + parser.print_help + sys.exit(-5) + mylist.append(f"{SCRIPT_DIR}/chroot_includes.lst") mylist.append(f"{SCRIPT_DIR}/chroot_minimal.lst") @@ -380,7 +389,7 @@ if __name__ == '__main__': # If chroot types were specified, then use those for arg in args.chroot_type: print(f"Chroot type is: {arg}") - + CHROOT_LIST = arg # add chroot prefix if it doesn't exist @@ -391,13 +400,8 @@ if __name__ == '__main__': if not CHROOT_LIST.endswith('.lst'): CHROOT_LIST = f"{CHROOT_LIST}.lst" - # check that the .lst file exists - if not os.path.isfile(CHROOT_LIST): - print(f"{CHROOT_LIST} cannot be found in {os.cwd}") - sys.exit(-7) - else: - # append file name to end of list - mylist.append(os.readlink(CHROOT_LIST)) + # append file name to end of list + mylist.append(CHROOT_LIST) logging.debug(f"Number of elements in the list: {len(mylist)}") logging.debug(f"List contents: {mylist}") From e1164d191e348eca7e509a32bd8fb4defc2c90c9 Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Mon, 8 Feb 2021 15:19:50 -0600 Subject: [PATCH 21/31] fixup! mknod FileNotFound Error --- chroot_setup | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/chroot_setup b/chroot_setup index cd6e322..e93f6ec 100644 --- a/chroot_setup +++ b/chroot_setup @@ -122,7 +122,11 @@ def chroot_mknod (line: str): print(f"os.remove({args.chroot_directory}{node})") print(f"os.mknod({args.chroot_directory}{node}, {mode}, {device})") if not CHROOT_DEBUG: - os.remove(f"{args.chroot_directory}{node}") + try: + os.remove(f"{args.chroot_directory}{node}") + except FileNotFoundError: + pass + os.mknod(f"{args.chroot_directory}{node}", mode, device) # :cp From ffb07eff394f7a01ab0520554aaa43de7faef3f3 Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Mon, 8 Feb 2021 21:22:46 -0600 Subject: [PATCH 22/31] fixup! Process -g (globals) args properly --- chroot_setup | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/chroot_setup b/chroot_setup index e93f6ec..b4f119b 100644 --- a/chroot_setup +++ b/chroot_setup @@ -7,6 +7,7 @@ import shutil import logging import stat import subprocess +import re from string import Template from enum import Enum @@ -246,6 +247,11 @@ def chroot_setup (chroot_lst): action = None # Iterate over all lines in the file, executing actions where encountered for line in lst_file: + if args.globals: + for key in globals_dictionary: + # sub placholders with values + line = re.sub(key, globals_dictionary[key], line) + line = line.strip() # Skip blank lines and comments @@ -422,15 +428,8 @@ if __name__ == '__main__': print("=====================================") print(f"setting up based on {chroot_file}") print("=====================================") - - for key in globals_dictionary: - os.environ[key] = globals_dictionary[key] - chroot_setup(chroot_file) - for key in globals_dictionary: - del os.environ[key] - os.makedirs(f"{args.chroot_directory}/QOpenSys/etc", exist_ok=True) etc_profile = (f"{args.chroot_directory}/QOpenSys/etc/profile") try: From ca5966b31503a2efc615052e4b7ed9c409878d51 Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Wed, 10 Feb 2021 17:54:34 -0600 Subject: [PATCH 23/31] fixup! Use globals and naming scheme for action handlers --- chroot_setup | 40 ++++++++++++++++++---------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/chroot_setup b/chroot_setup index b4f119b..ab321ca 100644 --- a/chroot_setup +++ b/chroot_setup @@ -242,6 +242,9 @@ def chroot_sh(line: str): # :file # Parses and executes additional .lst files +def chroot_file(chroot_lst: str): + chroot_setup(chroot_lst) + def chroot_setup (chroot_lst): with open(chroot_lst, 'r') as lst_file: action = None @@ -260,31 +263,24 @@ def chroot_setup (chroot_lst): # Determine action elif line.startswith(':'): - action = actions.get(line, None) + # We enforce consistent function naming scheme for our action + # handlers. Each handler is prefixed with "chroot_" followed by the + # action name. The lst files prefix actions with ":" so we determine + # the action handler function name by prefixing it with "chroot_" and + # appending the action after the ":" from the line. + function = f"chroot_{line[1:]}" + try: + # use the globals dict to resolve action function handler + action = globals()[function] + except KeyError: + print(f"Skipping invalid action: {line}") + action = None # Execute action else: if action is not None: action(line) -# Mapping the .lst action keys to the functions that run on their values -actions = { - ':file' : chroot_setup, - ':mkdir' : chroot_mkdir, # done - ':ln_fix_rel' : chroot_ln_fix_rel, # done - ':ln_rel' : chroot_ln_rel, # done - ':ln' : chroot_ln, # done - ':mknod' : chroot_mknod, # done - ':cp_dir' : chroot_cp_dir, # done - ':cp' : chroot_cp, # done - ':chmod_dir' : chroot_chmod_dir, # done - ':chmod' : chroot_chmod, # done - ':chown_dir' : chroot_chown_dir, # done - ':chown' : chroot_chown, # done - ':system' : chroot_system, # done - ':sh' : chroot_sh # done -} - # Run an initial check on the environment, ensuring that we are running on IBM i # and setting environment variables def initial_check(): @@ -424,11 +420,11 @@ if __name__ == '__main__': global_tokens = global_var.split('=') globals_dictionary[global_tokens[0]] = global_tokens[1] - for chroot_file in mylist: + for lst_file in mylist: print("=====================================") - print(f"setting up based on {chroot_file}") + print(f"setting up based on {lst_file}") print("=====================================") - chroot_setup(chroot_file) + chroot_setup(lst_file) os.makedirs(f"{args.chroot_directory}/QOpenSys/etc", exist_ok=True) etc_profile = (f"{args.chroot_directory}/QOpenSys/etc/profile") From 1991e2648aadeef0d3265b559550dbcd7c29b817 Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Wed, 10 Feb 2021 18:24:10 -0600 Subject: [PATCH 24/31] fixup! Remove CHROOT_DEBUG checks --- chroot_setup | 85 ++++++++++++++++++++-------------------------------- 1 file changed, 33 insertions(+), 52 deletions(-) diff --git a/chroot_setup b/chroot_setup index ab321ca..2869fc3 100644 --- a/chroot_setup +++ b/chroot_setup @@ -29,14 +29,11 @@ print(""" ##### ####### # ##### # """) -CHROOT_DEBUG : bool = False - # :mkdir # Make a directory inside the chroot, as well as all intermediary directories def chroot_mkdir (dir: str): print(f"os.makedirs({args.chroot_directory}{dir}, exist_ok=True)") - if not CHROOT_DEBUG: - os.makedirs(f"{args.chroot_directory}{dir}", exist_ok=True) + os.makedirs(f"{args.chroot_directory}{dir}", exist_ok=True) # :ln # Create an absolute symlink. We don't have to go inside the chroot, since the @@ -51,8 +48,7 @@ def chroot_ln (line: str): target, link_name = ln_command print(f"os.symlink({target}, {args.chroot_directory}{link_name})") - if not CHROOT_DEBUG: - os.symlink(target, f"{args.chroot_directory}{link_name}") + os.symlink(target, f"{args.chroot_directory}{link_name}") # :ln_rel # Create a relative symlink in the chroot that mirrors a relative symlink that @@ -69,10 +65,9 @@ def chroot_ln_rel (line: str): here = os.getcwd() print(f"os.chdir({args.chroot_directory}{directory})") print(f"os.symlink({target}, {basename})") - if not CHROOT_DEBUG: - os.chdir(f"{args.chroot_directory}{mydir}") - os.symlink(target, basename) - os.chdir(here) + os.chdir(f"{args.chroot_directory}{mydir}") + os.symlink(target, basename) + os.chdir(here) # :ln # Create a relative symlink inside of the chroot, specifying where the link @@ -91,10 +86,9 @@ def chroot_ln_fix_rel (line: str): print(f"os.chdir({args.chroot_directory}{directory})") print(f"os.symlink{target}, {basename})") print(f"os.chdir({here})") - if not CHROOT_DEBUG: - os.chdir(f"{args.chroot_directory}{mydir}") - os.symlink(target, basename) - os.chdir(here) + os.chdir(f"{args.chroot_directory}{mydir}") + os.symlink(target, basename) + os.chdir(here) # :mknod # Create a node with a given name, type, and major and minor number @@ -122,38 +116,35 @@ def chroot_mknod (line: str): print(f"os.remove({args.chroot_directory}{node})") print(f"os.mknod({args.chroot_directory}{node}, {mode}, {device})") - if not CHROOT_DEBUG: - try: - os.remove(f"{args.chroot_directory}{node}") - except FileNotFoundError: - pass + try: + os.remove(f"{args.chroot_directory}{node}") + except FileNotFoundError: + pass - os.mknod(f"{args.chroot_directory}{node}", mode, device) + os.mknod(f"{args.chroot_directory}{node}", mode, device) # :cp # Copy a file from outside the chroot to inside the chroot, keeping the same # (relative) location. def chroot_cp (line: str): print(f"shutil.copy({line}, {args.chroot_directory}{line})") - if not CHROOT_DEBUG: - shutil.copy(line, f"{args.chroot_directory}{line}") + shutil.copy(line, f"{args.chroot_directory}{line}") # :cp_dir # Copy a directory from outside the chroot to inside the chroot, keeping the # same (relative) location. def chroot_cp_dir (line: str): print(f"shutil.copytree({line}, {args.chroot_directory}{line})") - if not CHROOT_DEBUG: - # In Python v3.8+, shutil.copytree has a dirs_exist_ok keyword argument that - # prevents a FileExistsError when the destination directory exists. - # Unfortunately we are currently on v3.6.12, so we have to delete any - # directory that exists at that location. - if sys.version_info >= (3,8): - shutil.copytree(line, f"{args.chroot_directory}{line}", dirs_exist=True) - else: - if os.path.exists(f"{args.chroot_directory}{line}"): - shutil.rmtree(f"{args.chroot_directory}{line}") - shutil.copytree(line, f"{args.chroot_directory}{line}") + # In Python v3.8+, shutil.copytree has a dirs_exist_ok keyword argument that + # prevents a FileExistsError when the destination directory exists. + # Unfortunately we are currently on v3.6.12, so we have to delete any + # directory that exists at that location. + if sys.version_info >= (3,8): + shutil.copytree(line, f"{args.chroot_directory}{line}", dirs_exist=True) + else: + if os.path.exists(f"{args.chroot_directory}{line}"): + shutil.rmtree(f"{args.chroot_directory}{line}") + shutil.copytree(line, f"{args.chroot_directory}{line}") # :chmod # Change the permissions on a file in the chroot. @@ -166,8 +157,7 @@ def chroot_chmod (line: str): mode = int(chmod_command[0], 8) chmod_file = f"{args.chroot_directory}{chmod_command[1]}" printf(f"os.chmod({chmod_file}, {mode})") - if not CHROOT_DEBUG: - os.chmod(chmod_file, mode) + os.chmod(chmod_file, mode) # :chmod_dir # Change the permissions on a directory and everything inside it in the chroot. @@ -182,12 +172,10 @@ def chroot_chmod_dir (line: str): for root, dirs, files in os.walk(f"{args.chroot_directory}{chmod_dir}"): for dir in dirs: print(f"os.chmod({os.path.join(root, dir)}, {int(mode, 8)})") - if not CHROOT_DEBUG: - os.chmod(os.path.join(root, dir), int(mode, 8)) + os.chmod(os.path.join(root, dir), int(mode, 8)) for file in files: print(f"os.chmod({os.path.join(root, file)}, {int(mode, 8)})") - if not CHROOT_DEBUG: - os.chmod(os.path.join(root, file), int(mode, 8)) + os.chmod(os.path.join(root, file), int(mode, 8)) # :chown # Change ownership of a file in the chroot @@ -200,8 +188,7 @@ def chroot_chown (line: str): user = chown_command[0] chown_file = f"{args.chroot_directory}{chown_command[1]}" printf(f"os.chown({args.chroot_directory}{chown_file}, {user})") - if not CHROOT_DEBUG: - os.chown(f"{args.chroot_directory}{chown_file, user}") + os.chown(f"{args.chroot_directory}{chown_file, user}") # :chown_dir # Change ownership of a directory and everything inside it in the chroot. @@ -216,29 +203,25 @@ def chroot_chown_dir (line: str): for root, dirs, files in os.walk(f"{args.chroot_directory}{chown_directory}"): for dir in dirs: printf(f"os.chown({os.path.join(root, dir)}, {user})") - if not CHROOT_DEBUG: - os.chown(os.path.join(root, dir), user) + os.chown(os.path.join(root, dir), user) for file in files: printf(f"os.chown({os.path.join(root, file)}, {user})") - if not CHROOT_DEBUG: - os.chown(os.path.join(root, file), user) + os.chown(os.path.join(root, file), user) # :system # Executes a line from a .lst file using the /QOpenSys/usr/bin/system utility def chroot_system(line: str): line = line.rstrip() print(f"system -i {line}") - if not CHROOT_DEBUG: - subprocess.run(['system', '-i', line], check=True) + subprocess.run(['system', '-i', line], check=True) # :sh # Executes a line from a .lst file using Pythons os.system function, which is # run "by calling the Standard C function system()." def chroot_sh(line: str): print(line) - if not CHROOT_DEBUG: - os.system(line) - subprocess.run(line.split(), check=True) + os.system(line) + subprocess.run(line.split(), check=True) # :file # Parses and executes additional .lst files @@ -285,13 +268,11 @@ def chroot_setup (chroot_lst): # and setting environment variables def initial_check(): if (os.uname().sysname == 'OS400'): - # CHROOT_DEBUG = False print("**********************") print("Live IBM i session (changes made).") print("**********************") else: - # CHROOT_DEBUG = True print("**********************") print("Not IBM i, no action is taken (debug flow purpose only).") print("**********************") From cc59e6f1f368b5c4b1042f1f1d7b91ae16afa0ff Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Wed, 10 Feb 2021 18:51:02 -0600 Subject: [PATCH 25/31] fixup! Add flake8 lint action --- .github/workflows/pythonpackage.yml | 37 +++++++++++++++++++++++++++++ requirements.txt | 1 + 2 files changed, 38 insertions(+) create mode 100644 .github/workflows/pythonpackage.yml create mode 100644 requirements.txt diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml new file mode 100644 index 0000000..f098155 --- /dev/null +++ b/.github/workflows/pythonpackage.yml @@ -0,0 +1,37 @@ +name: ibmichroot CI + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + + runs-on: ubuntu-latest + strategy: + matrix: + python-version: [3.6, 3.7, 3.8] + + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + - name: Lint with flake8 + run: | + # stop the build if there are Python syntax errors or undefined names + flake8 chroot_setup --count --select=E9,F63,F7,F82 --show-source --statistics + # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide + flake8 chroot_setup --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + # TODO add tests + #- name: Test with pytest + #run: | + # pytest + diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..afd512c --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +flake8 >= 3.8.4 From 6022fb95d707ea76cc98758966f634bf83e07ba9 Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Wed, 10 Feb 2021 19:15:51 -0600 Subject: [PATCH 26/31] fixup! Initial flake8 linter undefined names --- chroot_setup | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/chroot_setup b/chroot_setup index 2869fc3..624b351 100644 --- a/chroot_setup +++ b/chroot_setup @@ -65,7 +65,7 @@ def chroot_ln_rel (line: str): here = os.getcwd() print(f"os.chdir({args.chroot_directory}{directory})") print(f"os.symlink({target}, {basename})") - os.chdir(f"{args.chroot_directory}{mydir}") + os.chdir(f"{args.chroot_directory}") os.symlink(target, basename) os.chdir(here) @@ -86,7 +86,7 @@ def chroot_ln_fix_rel (line: str): print(f"os.chdir({args.chroot_directory}{directory})") print(f"os.symlink{target}, {basename})") print(f"os.chdir({here})") - os.chdir(f"{args.chroot_directory}{mydir}") + os.chdir(f"{args.chroot_directory}") os.symlink(target, basename) os.chdir(here) @@ -156,7 +156,7 @@ def chroot_chmod (line: str): mode = int(chmod_command[0], 8) chmod_file = f"{args.chroot_directory}{chmod_command[1]}" - printf(f"os.chmod({chmod_file}, {mode})") + print(f"os.chmod({chmod_file}, {mode})") os.chmod(chmod_file, mode) # :chmod_dir @@ -187,7 +187,7 @@ def chroot_chown (line: str): user = chown_command[0] chown_file = f"{args.chroot_directory}{chown_command[1]}" - printf(f"os.chown({args.chroot_directory}{chown_file}, {user})") + print(f"os.chown({args.chroot_directory}{chown_file}, {user})") os.chown(f"{args.chroot_directory}{chown_file, user}") # :chown_dir @@ -202,10 +202,10 @@ def chroot_chown_dir (line: str): chown_directory = f"{args.chroot_directory}{chown_command[1]}" for root, dirs, files in os.walk(f"{args.chroot_directory}{chown_directory}"): for dir in dirs: - printf(f"os.chown({os.path.join(root, dir)}, {user})") + print(f"os.chown({os.path.join(root, dir)}, {user})") os.chown(os.path.join(root, dir), user) for file in files: - printf(f"os.chown({os.path.join(root, file)}, {user})") + print(f"os.chown({os.path.join(root, file)}, {user})") os.chown(os.path.join(root, file), user) # :system From ce3ddd605fcee5da8187609982969a01dea4c18e Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Wed, 17 Feb 2021 11:10:36 -0600 Subject: [PATCH 27/31] fixup! indention multiple of 4 --- chroot_setup | 588 +++++++++++++++++++++++++-------------------------- 1 file changed, 294 insertions(+), 294 deletions(-) diff --git a/chroot_setup b/chroot_setup index 624b351..4f097a3 100644 --- a/chroot_setup +++ b/chroot_setup @@ -32,398 +32,398 @@ print(""" # :mkdir # Make a directory inside the chroot, as well as all intermediary directories def chroot_mkdir (dir: str): - print(f"os.makedirs({args.chroot_directory}{dir}, exist_ok=True)") - os.makedirs(f"{args.chroot_directory}{dir}", exist_ok=True) + print(f"os.makedirs({args.chroot_directory}{dir}, exist_ok=True)") + os.makedirs(f"{args.chroot_directory}{dir}", exist_ok=True) # :ln # Create an absolute symlink. We don't have to go inside the chroot, since the # links are resolved as they are used. The target doesn't even have to exist, # Python won't check and therefore won't throw an error. def chroot_ln (line: str): - ln_command = line.split() + ln_command = line.split() - if not len(ln_command) == 2: - raise ValueError(":ln action expects 2 arguments!") + if not len(ln_command) == 2: + raise ValueError(":ln action expects 2 arguments!") - target, link_name = ln_command + target, link_name = ln_command - print(f"os.symlink({target}, {args.chroot_directory}{link_name})") - os.symlink(target, f"{args.chroot_directory}{link_name}") + print(f"os.symlink({target}, {args.chroot_directory}{link_name})") + os.symlink(target, f"{args.chroot_directory}{link_name}") # :ln_rel # Create a relative symlink in the chroot that mirrors a relative symlink that # exists outside of the chroot. def chroot_ln_rel (line: str): - ln_command = line.split() + ln_command = line.split() - if not len(ln_command) == 1: - raise ValueError(":ln_rel action expects 1 argument!") + if not len(ln_command) == 1: + raise ValueError(":ln_rel action expects 1 argument!") - directory = os.path.dirname(line) - basename = os.path.basename(line) - target = os.readlink(line) - here = os.getcwd() - print(f"os.chdir({args.chroot_directory}{directory})") - print(f"os.symlink({target}, {basename})") - os.chdir(f"{args.chroot_directory}") - os.symlink(target, basename) - os.chdir(here) + directory = os.path.dirname(line) + basename = os.path.basename(line) + target = os.readlink(line) + here = os.getcwd() + print(f"os.chdir({args.chroot_directory}{directory})") + print(f"os.symlink({target}, {basename})") + os.chdir(f"{args.chroot_directory}") + os.symlink(target, basename) + os.chdir(here) # :ln # Create a relative symlink inside of the chroot, specifying where the link # should be pointed to. This means you can change a relative symlink you pass # in, or simply create a relative symlink where one didn't exist before def chroot_ln_fix_rel (line: str): - ln_command = line.split() - - if not len(ln_command) == 2: - raise ValueError(":ln_fix_rel action expects 2 arguments!") - - target, link_name = ln_command - directory = os.path.dirname(link_name) - basename = os.path.basename(link_name) - here = os.getcwd() - print(f"os.chdir({args.chroot_directory}{directory})") - print(f"os.symlink{target}, {basename})") - print(f"os.chdir({here})") - os.chdir(f"{args.chroot_directory}") - os.symlink(target, basename) - os.chdir(here) + ln_command = line.split() + + if not len(ln_command) == 2: + raise ValueError(":ln_fix_rel action expects 2 arguments!") + + target, link_name = ln_command + directory = os.path.dirname(link_name) + basename = os.path.basename(link_name) + here = os.getcwd() + print(f"os.chdir({args.chroot_directory}{directory})") + print(f"os.symlink{target}, {basename})") + print(f"os.chdir({here})") + os.chdir(f"{args.chroot_directory}") + os.symlink(target, basename) + os.chdir(here) # :mknod # Create a node with a given name, type, and major and minor number def chroot_mknod (line: str): - # We are passed a mknod terminal commmand. Need to parse it to make it work - # with os.mknod. - mknod_command = line.split() + # We are passed a mknod terminal commmand. Need to parse it to make it work + # with os.mknod. + mknod_command = line.split() - if not len(mknod_command) == 4: - raise ValueError(":mknod action expects 4 arguments!") + if not len(mknod_command) == 4: + raise ValueError(":mknod action expects 4 arguments!") - node: str = mknod_command[0] + node: str = mknod_command[0] - # we only support creating character special devices - if mknod_command[1] != 'c': - print("Unrecognized mknod type; Valid type is 'c'") - sys.exit(-6) + # we only support creating character special devices + if mknod_command[1] != 'c': + print("Unrecognized mknod type; Valid type is 'c'") + sys.exit(-6) - mode = 0o644 | stat.S_IFCHR + mode = 0o644 | stat.S_IFCHR - # device major and minor numbers are created through os.makedev - major = mknod_command[2] - minor = mknod_command[3] - device = os.makedev(int(major), int(minor)) + # device major and minor numbers are created through os.makedev + major = mknod_command[2] + minor = mknod_command[3] + device = os.makedev(int(major), int(minor)) - print(f"os.remove({args.chroot_directory}{node})") - print(f"os.mknod({args.chroot_directory}{node}, {mode}, {device})") - try: - os.remove(f"{args.chroot_directory}{node}") - except FileNotFoundError: - pass + print(f"os.remove({args.chroot_directory}{node})") + print(f"os.mknod({args.chroot_directory}{node}, {mode}, {device})") + try: + os.remove(f"{args.chroot_directory}{node}") + except FileNotFoundError: + pass - os.mknod(f"{args.chroot_directory}{node}", mode, device) + os.mknod(f"{args.chroot_directory}{node}", mode, device) # :cp # Copy a file from outside the chroot to inside the chroot, keeping the same # (relative) location. def chroot_cp (line: str): - print(f"shutil.copy({line}, {args.chroot_directory}{line})") - shutil.copy(line, f"{args.chroot_directory}{line}") + print(f"shutil.copy({line}, {args.chroot_directory}{line})") + shutil.copy(line, f"{args.chroot_directory}{line}") # :cp_dir # Copy a directory from outside the chroot to inside the chroot, keeping the # same (relative) location. def chroot_cp_dir (line: str): - print(f"shutil.copytree({line}, {args.chroot_directory}{line})") - # In Python v3.8+, shutil.copytree has a dirs_exist_ok keyword argument that - # prevents a FileExistsError when the destination directory exists. - # Unfortunately we are currently on v3.6.12, so we have to delete any - # directory that exists at that location. - if sys.version_info >= (3,8): - shutil.copytree(line, f"{args.chroot_directory}{line}", dirs_exist=True) - else: - if os.path.exists(f"{args.chroot_directory}{line}"): - shutil.rmtree(f"{args.chroot_directory}{line}") - shutil.copytree(line, f"{args.chroot_directory}{line}") + print(f"shutil.copytree({line}, {args.chroot_directory}{line})") + # In Python v3.8+, shutil.copytree has a dirs_exist_ok keyword argument that + # prevents a FileExistsError when the destination directory exists. + # Unfortunately we are currently on v3.6.12, so we have to delete any + # directory that exists at that location. + if sys.version_info >= (3,8): + shutil.copytree(line, f"{args.chroot_directory}{line}", dirs_exist=True) + else: + if os.path.exists(f"{args.chroot_directory}{line}"): + shutil.rmtree(f"{args.chroot_directory}{line}") + shutil.copytree(line, f"{args.chroot_directory}{line}") # :chmod # Change the permissions on a file in the chroot. def chroot_chmod (line: str): - chmod_command = line.split() + chmod_command = line.split() - if not len(chmod_command) == 2: - raise ValueError(":chmod action expects 2 arguments!") + if not len(chmod_command) == 2: + raise ValueError(":chmod action expects 2 arguments!") - mode = int(chmod_command[0], 8) - chmod_file = f"{args.chroot_directory}{chmod_command[1]}" - print(f"os.chmod({chmod_file}, {mode})") - os.chmod(chmod_file, mode) + mode = int(chmod_command[0], 8) + chmod_file = f"{args.chroot_directory}{chmod_command[1]}" + print(f"os.chmod({chmod_file}, {mode})") + os.chmod(chmod_file, mode) # :chmod_dir # Change the permissions on a directory and everything inside it in the chroot. def chroot_chmod_dir (line: str): - chmod_command = line.split() + chmod_command = line.split() - if not len(chmod_command) == 2: - raise ValueError(":chmod_dir action expects 2 arguments!") + if not len(chmod_command) == 2: + raise ValueError(":chmod_dir action expects 2 arguments!") - mode = int(chmod_command[0], 8) - chmod_dir = f"{args.chroot_directory}{chmod_command[1]}" - for root, dirs, files in os.walk(f"{args.chroot_directory}{chmod_dir}"): - for dir in dirs: - print(f"os.chmod({os.path.join(root, dir)}, {int(mode, 8)})") - os.chmod(os.path.join(root, dir), int(mode, 8)) - for file in files: - print(f"os.chmod({os.path.join(root, file)}, {int(mode, 8)})") - os.chmod(os.path.join(root, file), int(mode, 8)) + mode = int(chmod_command[0], 8) + chmod_dir = f"{args.chroot_directory}{chmod_command[1]}" + for root, dirs, files in os.walk(f"{args.chroot_directory}{chmod_dir}"): + for dir in dirs: + print(f"os.chmod({os.path.join(root, dir)}, {int(mode, 8)})") + os.chmod(os.path.join(root, dir), int(mode, 8)) + for file in files: + print(f"os.chmod({os.path.join(root, file)}, {int(mode, 8)})") + os.chmod(os.path.join(root, file), int(mode, 8)) # :chown # Change ownership of a file in the chroot def chroot_chown (line: str): - chown_command = line.split() + chown_command = line.split() - if not len(chown_command) == 2: - raise ValueError(":chown action expect 2 arguments!") + if not len(chown_command) == 2: + raise ValueError(":chown action expect 2 arguments!") - user = chown_command[0] - chown_file = f"{args.chroot_directory}{chown_command[1]}" - print(f"os.chown({args.chroot_directory}{chown_file}, {user})") - os.chown(f"{args.chroot_directory}{chown_file, user}") + user = chown_command[0] + chown_file = f"{args.chroot_directory}{chown_command[1]}" + print(f"os.chown({args.chroot_directory}{chown_file}, {user})") + os.chown(f"{args.chroot_directory}{chown_file, user}") # :chown_dir # Change ownership of a directory and everything inside it in the chroot. def chroot_chown_dir (line: str): - chown_command = line.split() + chown_command = line.split() - if not len(chown_command) == 2: - raise ValueError(":chown_dir action expect 2 arguments!") + if not len(chown_command) == 2: + raise ValueError(":chown_dir action expect 2 arguments!") - user = chown_command[0] - chown_directory = f"{args.chroot_directory}{chown_command[1]}" - for root, dirs, files in os.walk(f"{args.chroot_directory}{chown_directory}"): - for dir in dirs: - print(f"os.chown({os.path.join(root, dir)}, {user})") - os.chown(os.path.join(root, dir), user) - for file in files: - print(f"os.chown({os.path.join(root, file)}, {user})") - os.chown(os.path.join(root, file), user) + user = chown_command[0] + chown_directory = f"{args.chroot_directory}{chown_command[1]}" + for root, dirs, files in os.walk(f"{args.chroot_directory}{chown_directory}"): + for dir in dirs: + print(f"os.chown({os.path.join(root, dir)}, {user})") + os.chown(os.path.join(root, dir), user) + for file in files: + print(f"os.chown({os.path.join(root, file)}, {user})") + os.chown(os.path.join(root, file), user) # :system # Executes a line from a .lst file using the /QOpenSys/usr/bin/system utility def chroot_system(line: str): - line = line.rstrip() - print(f"system -i {line}") - subprocess.run(['system', '-i', line], check=True) + line = line.rstrip() + print(f"system -i {line}") + subprocess.run(['system', '-i', line], check=True) # :sh # Executes a line from a .lst file using Pythons os.system function, which is # run "by calling the Standard C function system()." def chroot_sh(line: str): - print(line) - os.system(line) - subprocess.run(line.split(), check=True) + print(line) + os.system(line) + subprocess.run(line.split(), check=True) # :file # Parses and executes additional .lst files def chroot_file(chroot_lst: str): - chroot_setup(chroot_lst) + chroot_setup(chroot_lst) def chroot_setup (chroot_lst): - with open(chroot_lst, 'r') as lst_file: - action = None - # Iterate over all lines in the file, executing actions where encountered - for line in lst_file: - if args.globals: - for key in globals_dictionary: - # sub placholders with values - line = re.sub(key, globals_dictionary[key], line) - - line = line.strip() - - # Skip blank lines and comments - if not line or line.startswith('#'): - continue - - # Determine action - elif line.startswith(':'): - # We enforce consistent function naming scheme for our action - # handlers. Each handler is prefixed with "chroot_" followed by the - # action name. The lst files prefix actions with ":" so we determine - # the action handler function name by prefixing it with "chroot_" and - # appending the action after the ":" from the line. - function = f"chroot_{line[1:]}" - try: - # use the globals dict to resolve action function handler - action = globals()[function] - except KeyError: - print(f"Skipping invalid action: {line}") - action = None - - # Execute action - else: - if action is not None: - action(line) + with open(chroot_lst, 'r') as lst_file: + action = None + # Iterate over all lines in the file, executing actions where encountered + for line in lst_file: + if args.globals: + for key in globals_dictionary: + # sub placholders with values + line = re.sub(key, globals_dictionary[key], line) + + line = line.strip() + + # Skip blank lines and comments + if not line or line.startswith('#'): + continue + + # Determine action + elif line.startswith(':'): + # We enforce consistent function naming scheme for our action + # handlers. Each handler is prefixed with "chroot_" followed by the + # action name. The lst files prefix actions with ":" so we determine + # the action handler function name by prefixing it with "chroot_" and + # appending the action after the ":" from the line. + function = f"chroot_{line[1:]}" + try: + # use the globals dict to resolve action function handler + action = globals()[function] + except KeyError: + print(f"Skipping invalid action: {line}") + action = None + + # Execute action + else: + if action is not None: + action(line) # Run an initial check on the environment, ensuring that we are running on IBM i # and setting environment variables def initial_check(): - if (os.uname().sysname == 'OS400'): - print("**********************") - print("Live IBM i session (changes made).") - print("**********************") + if (os.uname().sysname == 'OS400'): + print("**********************") + print("Live IBM i session (changes made).") + print("**********************") - else: - print("**********************") - print("Not IBM i, no action is taken (debug flow purpose only).") - print("**********************") - sys.exit(-1) + else: + print("**********************") + print("Not IBM i, no action is taken (debug flow purpose only).") + print("**********************") + sys.exit(-1) # Install any yum packages passed with the -i flag def yum_install(package_list: list): - install_template = Template('/QOpenSys/pkgs/bin/yum $yes --installroot=$chroot_dir install $packages') - auto_yes = '-y' if args.auto_yes else '' - packages = " ".join(package_list) - command = install_template.substitute(yes=auto_yes, chroot_dir=args.chroot_directory, packages=packages) - logging.debug(command) - subprocess.run(command.split(), check=True) + install_template = Template('/QOpenSys/pkgs/bin/yum $yes --installroot=$chroot_dir install $packages') + auto_yes = '-y' if args.auto_yes else '' + packages = " ".join(package_list) + command = install_template.substitute(yes=auto_yes, chroot_dir=args.chroot_directory, packages=packages) + logging.debug(command) + subprocess.run(command.split(), check=True) def input_yes(*args, **kwargs): - return 'y' + return 'y' # # MAIN # if __name__ == '__main__': - parser = argparse.ArgumentParser() - # positional arguments - parser.add_argument("chroot_directory", metavar="CHROOT_DIRECTORY", help="The location of the chroot to be created") - parser.add_argument("chroot_type", metavar="CHROOT_TYPE", help="A list of .lst files to use for generating the chroot", nargs="*") - # optional arguments - parser.add_argument("-g", dest='globals', nargs='*', metavar="", help="Environment variables to set when creating the chroot") - parser.add_argument("-i", dest='yum_installs', nargs='*', metavar="", help="A list of packages for yum to install in the chroot") - parser.add_argument("-y", dest='auto_yes', action='store_true', help="Automatically answer yes to input prompts") - parser.add_argument("-v", dest='verbose', action='store_true', help="Print verbose output when running") - args = parser.parse_args() - parser.parse_args() - - CHROOT_DIR = "" - CHROOT_LIST = "" - SCRIPT_DIR = f"{os.path.dirname(os.path.realpath(__file__))}/config" - - print(SCRIPT_DIR) - - auto_yes = args.auto_yes - initial_check() - - # This is done because the arg may be a relative path name. - # Need to be done before any 'cd' - TEMP_DIR = os.path.realpath(args.chroot_directory) - print(TEMP_DIR) - - # if -v was passed, need to turn logging to DEBUG so all logging messages in the - # code are printed - if (args.verbose): - logging.basicConfig(level=logging.DEBUG) - - logging.debug(f"Script directory: {SCRIPT_DIR}") - os.chdir(SCRIPT_DIR) - logging.debug(f"PWD: {os.getcwd()}") - - if not TEMP_DIR.startswith('/QOpenSys/'): - print("\nERROR: [CHROOT DIRECTORY] Must begin with /QOpenSys/...\n") - parser.print_help - sys.exit(-2) - - CHROOT_DIR = TEMP_DIR - - if not os.path.isdir(CHROOT_DIR): - print(f"{CHROOT_DIR} does not exist.") - logging.debug(f"Creating directory at {CHROOT_DIR}") - os.mkdir(CHROOT_DIR) - else: - if args.auto_yes: - input = input_yes - - print(f"{CHROOT_DIR} directory already exists") - val = input("Would you like to continue chroot setup? [y/N]: ") - - if not val == "y": - print("Bye") - sys.exit(-4) - - - # Validate CHROOT TYPE Argument(s) - mylist = [] - - if not args.chroot_type: - # Only chroot_directory was provided to the script: - # Ask if minimal with includes chroot is desired - - if args.auto_yes: - input = input_yes - - val = input(f"Would you like to create a minimal chroot w/ includes @ {CHROOT_DIR}? [y/N]: ") - if not val == "y": - print("Specify your desired [CHROOT TYPE]") - parser.print_help - sys.exit(-5) - - mylist.append(f"{SCRIPT_DIR}/chroot_includes.lst") - mylist.append(f"{SCRIPT_DIR}/chroot_minimal.lst") - - else: - # If chroot types were specified, then use those - for arg in args.chroot_type: - print(f"Chroot type is: {arg}") - - CHROOT_LIST = arg - - # add chroot prefix if it doesn't exist - if not CHROOT_LIST.startswith('chroot'): - CHROOT_LIST = f"chroot_{CHROOT_LIST}" - - # check that the .lst file name was given - if not CHROOT_LIST.endswith('.lst'): - CHROOT_LIST = f"{CHROOT_LIST}.lst" - - # append file name to end of list - mylist.append(CHROOT_LIST) - - logging.debug(f"Number of elements in the list: {len(mylist)}") - logging.debug(f"List contents: {mylist}") - - # convert any global variables passed from a list of string "KEY=VALUE" to a - # dictionary holding "KEY": "VALUE" - globals_dictionary = {} - if args.globals: - for global_var in args.globals: - global_tokens = global_var.split('=') - globals_dictionary[global_tokens[0]] = global_tokens[1] - - for lst_file in mylist: - print("=====================================") - print(f"setting up based on {lst_file}") - print("=====================================") - chroot_setup(lst_file) - - os.makedirs(f"{args.chroot_directory}/QOpenSys/etc", exist_ok=True) - etc_profile = (f"{args.chroot_directory}/QOpenSys/etc/profile") - try: - with open(etc_profile, 'x') as profile: - print('Priming /QOpenSys/etc/profile') - print('PATH=/QOpenSys/pkgs/bin:$PATH', file=profile) - print('export PATH', file=profile) - print('OBJECT_MODE=64', file=profile) - print('export OBJECT_MODE', file=profile) - except FileExistsError: - logging.debug(f"{etc_profile} already exists") - - # perform installs if set - if args.yum_installs is not None: - yum_install(args.yum_installs) - - print(f""" + parser = argparse.ArgumentParser() + # positional arguments + parser.add_argument("chroot_directory", metavar="CHROOT_DIRECTORY", help="The location of the chroot to be created") + parser.add_argument("chroot_type", metavar="CHROOT_TYPE", help="A list of .lst files to use for generating the chroot", nargs="*") + # optional arguments + parser.add_argument("-g", dest='globals', nargs='*', metavar="", help="Environment variables to set when creating the chroot") + parser.add_argument("-i", dest='yum_installs', nargs='*', metavar="", help="A list of packages for yum to install in the chroot") + parser.add_argument("-y", dest='auto_yes', action='store_true', help="Automatically answer yes to input prompts") + parser.add_argument("-v", dest='verbose', action='store_true', help="Print verbose output when running") + args = parser.parse_args() + parser.parse_args() + + CHROOT_DIR = "" + CHROOT_LIST = "" + SCRIPT_DIR = f"{os.path.dirname(os.path.realpath(__file__))}/config" + + print(SCRIPT_DIR) + + auto_yes = args.auto_yes + initial_check() + + # This is done because the arg may be a relative path name. + # Need to be done before any 'cd' + TEMP_DIR = os.path.realpath(args.chroot_directory) + print(TEMP_DIR) + + # if -v was passed, need to turn logging to DEBUG so all logging messages in the + # code are printed + if (args.verbose): + logging.basicConfig(level=logging.DEBUG) + + logging.debug(f"Script directory: {SCRIPT_DIR}") + os.chdir(SCRIPT_DIR) + logging.debug(f"PWD: {os.getcwd()}") + + if not TEMP_DIR.startswith('/QOpenSys/'): + print("\nERROR: [CHROOT DIRECTORY] Must begin with /QOpenSys/...\n") + parser.print_help + sys.exit(-2) + + CHROOT_DIR = TEMP_DIR + + if not os.path.isdir(CHROOT_DIR): + print(f"{CHROOT_DIR} does not exist.") + logging.debug(f"Creating directory at {CHROOT_DIR}") + os.mkdir(CHROOT_DIR) + else: + if args.auto_yes: + input = input_yes + + print(f"{CHROOT_DIR} directory already exists") + val = input("Would you like to continue chroot setup? [y/N]: ") + + if not val == "y": + print("Bye") + sys.exit(-4) + + + # Validate CHROOT TYPE Argument(s) + mylist = [] + + if not args.chroot_type: + # Only chroot_directory was provided to the script: + # Ask if minimal with includes chroot is desired + + if args.auto_yes: + input = input_yes + + val = input(f"Would you like to create a minimal chroot w/ includes @ {CHROOT_DIR}? [y/N]: ") + if not val == "y": + print("Specify your desired [CHROOT TYPE]") + parser.print_help + sys.exit(-5) + + mylist.append(f"{SCRIPT_DIR}/chroot_includes.lst") + mylist.append(f"{SCRIPT_DIR}/chroot_minimal.lst") + + else: + # If chroot types were specified, then use those + for arg in args.chroot_type: + print(f"Chroot type is: {arg}") + + CHROOT_LIST = arg + + # add chroot prefix if it doesn't exist + if not CHROOT_LIST.startswith('chroot'): + CHROOT_LIST = f"chroot_{CHROOT_LIST}" + + # check that the .lst file name was given + if not CHROOT_LIST.endswith('.lst'): + CHROOT_LIST = f"{CHROOT_LIST}.lst" + + # append file name to end of list + mylist.append(CHROOT_LIST) + + logging.debug(f"Number of elements in the list: {len(mylist)}") + logging.debug(f"List contents: {mylist}") + + # convert any global variables passed from a list of string "KEY=VALUE" to a + # dictionary holding "KEY": "VALUE" + globals_dictionary = {} + if args.globals: + for global_var in args.globals: + global_tokens = global_var.split('=') + globals_dictionary[global_tokens[0]] = global_tokens[1] + + for lst_file in mylist: + print("=====================================") + print(f"setting up based on {lst_file}") + print("=====================================") + chroot_setup(lst_file) + + os.makedirs(f"{args.chroot_directory}/QOpenSys/etc", exist_ok=True) + etc_profile = (f"{args.chroot_directory}/QOpenSys/etc/profile") + try: + with open(etc_profile, 'x') as profile: + print('Priming /QOpenSys/etc/profile') + print('PATH=/QOpenSys/pkgs/bin:$PATH', file=profile) + print('export PATH', file=profile) + print('OBJECT_MODE=64', file=profile) + print('export OBJECT_MODE', file=profile) + except FileExistsError: + logging.debug(f"{etc_profile} already exists") + + # perform installs if set + if args.yum_installs is not None: + yum_install(args.yum_installs) + + print(f""" Done creating your chroot! From 2ec264112a6f031bf4d1f9100ef2ee1707075c31 Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Wed, 17 Feb 2021 12:09:28 -0600 Subject: [PATCH 28/31] fixup! whitespace --- chroot_setup | 54 ++++++++++++++++++++++++++-------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/chroot_setup b/chroot_setup index 4f097a3..cf4af49 100644 --- a/chroot_setup +++ b/chroot_setup @@ -13,25 +13,25 @@ from enum import Enum print(""" ##### # # ###### ####### ####### ####### - # # # # # # # # # # # - # # # # # # # # # # - # ####### ###### # # # # # - # # # # # # # # # # - # # # # # # # # # # # - ##### # # # # ####### ####### # - - ##### ####### ####### # # ###### - # # # # # # # # - # # # # # # # - ##### ##### # # # ###### - # # # # # # - # # # # # # # + # # # # # # # # # # # + # # # # # # # # # # + # ####### ###### # # # # # + # # # # # # # # # # + # # # # # # # # # # # + ##### # # # # ####### ####### # + + ##### ####### ####### # # ###### + # # # # # # # # + # # # # # # # + ##### ##### # # # ###### + # # # # # # + # # # # # # # ##### ####### # ##### # """) # :mkdir # Make a directory inside the chroot, as well as all intermediary directories -def chroot_mkdir (dir: str): +def chroot_mkdir(dir: str): print(f"os.makedirs({args.chroot_directory}{dir}, exist_ok=True)") os.makedirs(f"{args.chroot_directory}{dir}", exist_ok=True) @@ -39,7 +39,7 @@ def chroot_mkdir (dir: str): # Create an absolute symlink. We don't have to go inside the chroot, since the # links are resolved as they are used. The target doesn't even have to exist, # Python won't check and therefore won't throw an error. -def chroot_ln (line: str): +def chroot_ln(line: str): ln_command = line.split() if not len(ln_command) == 2: @@ -53,7 +53,7 @@ def chroot_ln (line: str): # :ln_rel # Create a relative symlink in the chroot that mirrors a relative symlink that # exists outside of the chroot. -def chroot_ln_rel (line: str): +def chroot_ln_rel(line: str): ln_command = line.split() if not len(ln_command) == 1: @@ -73,7 +73,7 @@ def chroot_ln_rel (line: str): # Create a relative symlink inside of the chroot, specifying where the link # should be pointed to. This means you can change a relative symlink you pass # in, or simply create a relative symlink where one didn't exist before -def chroot_ln_fix_rel (line: str): +def chroot_ln_fix_rel(line: str): ln_command = line.split() if not len(ln_command) == 2: @@ -92,7 +92,7 @@ def chroot_ln_fix_rel (line: str): # :mknod # Create a node with a given name, type, and major and minor number -def chroot_mknod (line: str): +def chroot_mknod(line: str): # We are passed a mknod terminal commmand. Need to parse it to make it work # with os.mknod. mknod_command = line.split() @@ -100,7 +100,7 @@ def chroot_mknod (line: str): if not len(mknod_command) == 4: raise ValueError(":mknod action expects 4 arguments!") - node: str = mknod_command[0] + node: str = mknod_command[0] # we only support creating character special devices if mknod_command[1] != 'c': @@ -126,20 +126,20 @@ def chroot_mknod (line: str): # :cp # Copy a file from outside the chroot to inside the chroot, keeping the same # (relative) location. -def chroot_cp (line: str): +def chroot_cp(line: str): print(f"shutil.copy({line}, {args.chroot_directory}{line})") shutil.copy(line, f"{args.chroot_directory}{line}") # :cp_dir # Copy a directory from outside the chroot to inside the chroot, keeping the # same (relative) location. -def chroot_cp_dir (line: str): +def chroot_cp_dir(line: str): print(f"shutil.copytree({line}, {args.chroot_directory}{line})") # In Python v3.8+, shutil.copytree has a dirs_exist_ok keyword argument that # prevents a FileExistsError when the destination directory exists. # Unfortunately we are currently on v3.6.12, so we have to delete any # directory that exists at that location. - if sys.version_info >= (3,8): + if sys.version_info >= (3, 8): shutil.copytree(line, f"{args.chroot_directory}{line}", dirs_exist=True) else: if os.path.exists(f"{args.chroot_directory}{line}"): @@ -148,7 +148,7 @@ def chroot_cp_dir (line: str): # :chmod # Change the permissions on a file in the chroot. -def chroot_chmod (line: str): +def chroot_chmod(line: str): chmod_command = line.split() if not len(chmod_command) == 2: @@ -161,7 +161,7 @@ def chroot_chmod (line: str): # :chmod_dir # Change the permissions on a directory and everything inside it in the chroot. -def chroot_chmod_dir (line: str): +def chroot_chmod_dir(line: str): chmod_command = line.split() if not len(chmod_command) == 2: @@ -179,7 +179,7 @@ def chroot_chmod_dir (line: str): # :chown # Change ownership of a file in the chroot -def chroot_chown (line: str): +def chroot_chown(line: str): chown_command = line.split() if not len(chown_command) == 2: @@ -192,7 +192,7 @@ def chroot_chown (line: str): # :chown_dir # Change ownership of a directory and everything inside it in the chroot. -def chroot_chown_dir (line: str): +def chroot_chown_dir(line: str): chown_command = line.split() if not len(chown_command) == 2: @@ -228,7 +228,7 @@ def chroot_sh(line: str): def chroot_file(chroot_lst: str): chroot_setup(chroot_lst) -def chroot_setup (chroot_lst): +def chroot_setup(chroot_lst): with open(chroot_lst, 'r') as lst_file: action = None # Iterate over all lines in the file, executing actions where encountered From 140c9eb9767989042e40dde7da7be549e91b4b4e Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Wed, 17 Feb 2021 12:29:58 -0600 Subject: [PATCH 29/31] fixup! blank lines --- chroot_setup | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/chroot_setup b/chroot_setup index cf4af49..956602c 100644 --- a/chroot_setup +++ b/chroot_setup @@ -31,6 +31,8 @@ print(""" # :mkdir # Make a directory inside the chroot, as well as all intermediary directories + + def chroot_mkdir(dir: str): print(f"os.makedirs({args.chroot_directory}{dir}, exist_ok=True)") os.makedirs(f"{args.chroot_directory}{dir}", exist_ok=True) @@ -39,6 +41,8 @@ def chroot_mkdir(dir: str): # Create an absolute symlink. We don't have to go inside the chroot, since the # links are resolved as they are used. The target doesn't even have to exist, # Python won't check and therefore won't throw an error. + + def chroot_ln(line: str): ln_command = line.split() @@ -53,6 +57,8 @@ def chroot_ln(line: str): # :ln_rel # Create a relative symlink in the chroot that mirrors a relative symlink that # exists outside of the chroot. + + def chroot_ln_rel(line: str): ln_command = line.split() @@ -73,6 +79,8 @@ def chroot_ln_rel(line: str): # Create a relative symlink inside of the chroot, specifying where the link # should be pointed to. This means you can change a relative symlink you pass # in, or simply create a relative symlink where one didn't exist before + + def chroot_ln_fix_rel(line: str): ln_command = line.split() @@ -92,6 +100,8 @@ def chroot_ln_fix_rel(line: str): # :mknod # Create a node with a given name, type, and major and minor number + + def chroot_mknod(line: str): # We are passed a mknod terminal commmand. Need to parse it to make it work # with os.mknod. @@ -126,6 +136,8 @@ def chroot_mknod(line: str): # :cp # Copy a file from outside the chroot to inside the chroot, keeping the same # (relative) location. + + def chroot_cp(line: str): print(f"shutil.copy({line}, {args.chroot_directory}{line})") shutil.copy(line, f"{args.chroot_directory}{line}") @@ -133,6 +145,8 @@ def chroot_cp(line: str): # :cp_dir # Copy a directory from outside the chroot to inside the chroot, keeping the # same (relative) location. + + def chroot_cp_dir(line: str): print(f"shutil.copytree({line}, {args.chroot_directory}{line})") # In Python v3.8+, shutil.copytree has a dirs_exist_ok keyword argument that @@ -148,6 +162,8 @@ def chroot_cp_dir(line: str): # :chmod # Change the permissions on a file in the chroot. + + def chroot_chmod(line: str): chmod_command = line.split() @@ -161,6 +177,8 @@ def chroot_chmod(line: str): # :chmod_dir # Change the permissions on a directory and everything inside it in the chroot. + + def chroot_chmod_dir(line: str): chmod_command = line.split() @@ -179,6 +197,8 @@ def chroot_chmod_dir(line: str): # :chown # Change ownership of a file in the chroot + + def chroot_chown(line: str): chown_command = line.split() @@ -192,6 +212,8 @@ def chroot_chown(line: str): # :chown_dir # Change ownership of a directory and everything inside it in the chroot. + + def chroot_chown_dir(line: str): chown_command = line.split() @@ -210,6 +232,8 @@ def chroot_chown_dir(line: str): # :system # Executes a line from a .lst file using the /QOpenSys/usr/bin/system utility + + def chroot_system(line: str): line = line.rstrip() print(f"system -i {line}") @@ -218,6 +242,8 @@ def chroot_system(line: str): # :sh # Executes a line from a .lst file using Pythons os.system function, which is # run "by calling the Standard C function system()." + + def chroot_sh(line: str): print(line) os.system(line) @@ -225,9 +251,12 @@ def chroot_sh(line: str): # :file # Parses and executes additional .lst files + + def chroot_file(chroot_lst: str): chroot_setup(chroot_lst) + def chroot_setup(chroot_lst): with open(chroot_lst, 'r') as lst_file: action = None @@ -266,6 +295,8 @@ def chroot_setup(chroot_lst): # Run an initial check on the environment, ensuring that we are running on IBM i # and setting environment variables + + def initial_check(): if (os.uname().sysname == 'OS400'): print("**********************") @@ -288,9 +319,11 @@ def yum_install(package_list: list): logging.debug(command) subprocess.run(command.split(), check=True) + def input_yes(*args, **kwargs): return 'y' + # # MAIN # @@ -352,7 +385,6 @@ if __name__ == '__main__': print("Bye") sys.exit(-4) - # Validate CHROOT TYPE Argument(s) mylist = [] From 3888e541d641230dbe84087e38d4650d0cc3c823 Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Wed, 17 Feb 2021 13:11:27 -0600 Subject: [PATCH 30/31] fixup! unused enum import --- chroot_setup | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chroot_setup b/chroot_setup index 956602c..24fd53e 100644 --- a/chroot_setup +++ b/chroot_setup @@ -9,7 +9,7 @@ import stat import subprocess import re from string import Template -from enum import Enum + print(""" ##### # # ###### ####### ####### ####### From 6152a138afdbd0b70eb09403bae592d828d79e5d Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Wed, 17 Feb 2021 14:14:26 -0600 Subject: [PATCH 31/31] fixup! docstrings, line lengths, etc --- chroot_setup | 251 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 150 insertions(+), 101 deletions(-) diff --git a/chroot_setup b/chroot_setup index 24fd53e..d5d3df4 100644 --- a/chroot_setup +++ b/chroot_setup @@ -1,5 +1,9 @@ #!/QOpenSys/pkgs/bin/python3 +""" +Module to automate and simplifiy chroot environment creation +""" + import argparse import os import sys @@ -10,7 +14,6 @@ import subprocess import re from string import Template - print(""" ##### # # ###### ####### ####### ####### # # # # # # # # # # # @@ -29,21 +32,25 @@ print(""" ##### ####### # ##### # """) -# :mkdir -# Make a directory inside the chroot, as well as all intermediary directories - - -def chroot_mkdir(dir: str): - print(f"os.makedirs({args.chroot_directory}{dir}, exist_ok=True)") - os.makedirs(f"{args.chroot_directory}{dir}", exist_ok=True) -# :ln -# Create an absolute symlink. We don't have to go inside the chroot, since the -# links are resolved as they are used. The target doesn't even have to exist, -# Python won't check and therefore won't throw an error. +def chroot_mkdir(directory: str): + """ + Makes a directory inside the chroot, as well as all intermediary + directories + """ + # :mkdir + print(f"os.makedirs({args.chroot_directory}{directory}, exist_ok=True)") + os.makedirs(f"{args.chroot_directory}{directory}", exist_ok=True) def chroot_ln(line: str): + """ + Create an absolute symlink inside the chroot + """ + # We don't have to go inside the chroot, since the + # links are resolved as they are used. The target doesn't even have to + # exist, Python won't check and therefore won't throw an error. + # :ln ln_command = line.split() if not len(ln_command) == 2: @@ -54,12 +61,13 @@ def chroot_ln(line: str): print(f"os.symlink({target}, {args.chroot_directory}{link_name})") os.symlink(target, f"{args.chroot_directory}{link_name}") -# :ln_rel -# Create a relative symlink in the chroot that mirrors a relative symlink that -# exists outside of the chroot. - def chroot_ln_rel(line: str): + """ + Creates a relative symlink in the chroot that mirrors a relative symlink + that exists outside of the chroot. + """ + # :ln_rel ln_command = line.split() if not len(ln_command) == 1: @@ -75,13 +83,15 @@ def chroot_ln_rel(line: str): os.symlink(target, basename) os.chdir(here) -# :ln -# Create a relative symlink inside of the chroot, specifying where the link -# should be pointed to. This means you can change a relative symlink you pass -# in, or simply create a relative symlink where one didn't exist before - def chroot_ln_fix_rel(line: str): + """ + Create a relative symlink inside of the chroot, specifying where the link + should be pointed to. + """ + # This means you can change a relative symlink you pass in, or simply + # create a relative symlink where one didn't exist before + # :ln ln_command = line.split() if not len(ln_command) == 2: @@ -98,13 +108,15 @@ def chroot_ln_fix_rel(line: str): os.symlink(target, basename) os.chdir(here) -# :mknod -# Create a node with a given name, type, and major and minor number - def chroot_mknod(line: str): + """ + Create a node with a given name, type, and major and minor number. + Currently character is the only node type supported. + """ # We are passed a mknod terminal commmand. Need to parse it to make it work # with os.mknod. + # :mknod mknod_command = line.split() if not len(mknod_command) == 4: @@ -133,38 +145,44 @@ def chroot_mknod(line: str): os.mknod(f"{args.chroot_directory}{node}", mode, device) -# :cp -# Copy a file from outside the chroot to inside the chroot, keeping the same -# (relative) location. - def chroot_cp(line: str): + """ + Copy a file from outside the chroot to inside the chroot, keeping the same + (relative) location. + """ + # :cp print(f"shutil.copy({line}, {args.chroot_directory}{line})") shutil.copy(line, f"{args.chroot_directory}{line}") -# :cp_dir -# Copy a directory from outside the chroot to inside the chroot, keeping the -# same (relative) location. - def chroot_cp_dir(line: str): + """ + Copy a directory from outside the chroot to inside the chroot, keeping the + same (relative) location. + """ + # :cp_dir + print(f"shutil.copytree({line}, {args.chroot_directory}{line})") - # In Python v3.8+, shutil.copytree has a dirs_exist_ok keyword argument that - # prevents a FileExistsError when the destination directory exists. + # In Python v3.8+, shutil.copytree has a dirs_exist_ok keyword argument + # that prevents a FileExistsError when the destination directory exists. # Unfortunately we are currently on v3.6.12, so we have to delete any # directory that exists at that location. if sys.version_info >= (3, 8): - shutil.copytree(line, f"{args.chroot_directory}{line}", dirs_exist=True) + shutil.copytree(line, f"{args.chroot_directory}{line}", + dirs_exist=True) else: if os.path.exists(f"{args.chroot_directory}{line}"): shutil.rmtree(f"{args.chroot_directory}{line}") shutil.copytree(line, f"{args.chroot_directory}{line}") -# :chmod -# Change the permissions on a file in the chroot. - def chroot_chmod(line: str): + """ + Change the mode on a file in the chroot. + """ + # :chmod + chmod_command = line.split() if not len(chmod_command) == 2: @@ -175,11 +193,12 @@ def chroot_chmod(line: str): print(f"os.chmod({chmod_file}, {mode})") os.chmod(chmod_file, mode) -# :chmod_dir -# Change the permissions on a directory and everything inside it in the chroot. - def chroot_chmod_dir(line: str): + """ + Change the mode on a directory and everything inside it in the chroot. + """ + # :chmod_dir chmod_command = line.split() if not len(chmod_command) == 2: @@ -188,18 +207,19 @@ def chroot_chmod_dir(line: str): mode = int(chmod_command[0], 8) chmod_dir = f"{args.chroot_directory}{chmod_command[1]}" for root, dirs, files in os.walk(f"{args.chroot_directory}{chmod_dir}"): - for dir in dirs: - print(f"os.chmod({os.path.join(root, dir)}, {int(mode, 8)})") - os.chmod(os.path.join(root, dir), int(mode, 8)) + for directory in dirs: + print(f"os.chmod({os.path.join(root, directory)}, {int(mode, 8)})") + os.chmod(os.path.join(root, directory), int(mode, 8)) for file in files: print(f"os.chmod({os.path.join(root, file)}, {int(mode, 8)})") os.chmod(os.path.join(root, file), int(mode, 8)) -# :chown -# Change ownership of a file in the chroot - def chroot_chown(line: str): + """ + Change ownership of a file in the chroot + """ + # :chown chown_command = line.split() if not len(chown_command) == 2: @@ -210,11 +230,12 @@ def chroot_chown(line: str): print(f"os.chown({args.chroot_directory}{chown_file}, {user})") os.chown(f"{args.chroot_directory}{chown_file, user}") -# :chown_dir -# Change ownership of a directory and everything inside it in the chroot. - def chroot_chown_dir(line: str): + """ + Change ownership of a directory and everything inside it in the chroot. + """ + # :chown_dir chown_command = line.split() if not len(chown_command) == 2: @@ -222,45 +243,51 @@ def chroot_chown_dir(line: str): user = chown_command[0] chown_directory = f"{args.chroot_directory}{chown_command[1]}" - for root, dirs, files in os.walk(f"{args.chroot_directory}{chown_directory}"): - for dir in dirs: - print(f"os.chown({os.path.join(root, dir)}, {user})") - os.chown(os.path.join(root, dir), user) + for root, dirs, files in os.walk(f"{args.chroot_directory}" + f"{chown_directory}"): + for directory in dirs: + print(f"os.chown({os.path.join(root, directory)}, {user})") + os.chown(os.path.join(root, directory), user) for file in files: print(f"os.chown({os.path.join(root, file)}, {user})") os.chown(os.path.join(root, file), user) -# :system -# Executes a line from a .lst file using the /QOpenSys/usr/bin/system utility - def chroot_system(line: str): + """ + Executes a line from a .lst file using the system utility. + """ + # :system line = line.rstrip() print(f"system -i {line}") subprocess.run(['system', '-i', line], check=True) -# :sh -# Executes a line from a .lst file using Pythons os.system function, which is -# run "by calling the Standard C function system()." - def chroot_sh(line: str): + """ + Executes a command from a .lst file using Pythons subprocess.run function. + """ + # :sh print(line) os.system(line) subprocess.run(line.split(), check=True) -# :file -# Parses and executes additional .lst files - def chroot_file(chroot_lst: str): + """ + Parses and executes additional .lst files + """ + # :file chroot_setup(chroot_lst) def chroot_setup(chroot_lst): + """ + Parses and executes additional .lst files + """ with open(chroot_lst, 'r') as lst_file: action = None - # Iterate over all lines in the file, executing actions where encountered + # Iterate over all lines in the file, run actions where encountered for line in lst_file: if args.globals: for key in globals_dictionary: @@ -276,10 +303,11 @@ def chroot_setup(chroot_lst): # Determine action elif line.startswith(':'): # We enforce consistent function naming scheme for our action - # handlers. Each handler is prefixed with "chroot_" followed by the - # action name. The lst files prefix actions with ":" so we determine - # the action handler function name by prefixing it with "chroot_" and - # appending the action after the ":" from the line. + # handlers. Each handler is prefixed with "chroot_" followed by + # the action name. The lst files prefix actions with ":" so we + # determine the action handler function name by prefixing it + # with "chroot_" and appending the action after the + # ":" from the line. function = f"chroot_{line[1:]}" try: # use the globals dict to resolve action function handler @@ -293,12 +321,13 @@ def chroot_setup(chroot_lst): if action is not None: action(line) -# Run an initial check on the environment, ensuring that we are running on IBM i -# and setting environment variables - def initial_check(): - if (os.uname().sysname == 'OS400'): + """ + Run an initial check on the environment, ensuring that we are running on + IBM i + """ + if os.uname().sysname == 'OS400': print("**********************") print("Live IBM i session (changes made).") print("**********************") @@ -310,17 +339,26 @@ def initial_check(): sys.exit(-1) -# Install any yum packages passed with the -i flag def yum_install(package_list: list): - install_template = Template('/QOpenSys/pkgs/bin/yum $yes --installroot=$chroot_dir install $packages') + """ + Installs specified yum packages within the chroot. + """ + install_template = Template("/QOpenSys/pkgs/bin/yum $yes " + "--installroot=$chroot_dir install $packages") auto_yes = '-y' if args.auto_yes else '' packages = " ".join(package_list) - command = install_template.substitute(yes=auto_yes, chroot_dir=args.chroot_directory, packages=packages) + command = install_template.substitute(yes=auto_yes, + chroot_dir=args.chroot_directory, + packages=packages) logging.debug(command) subprocess.run(command.split(), check=True) def input_yes(*args, **kwargs): + """ + Helper function used when auto yes mode is enabled. This function simple + returns 'y'. + """ return 'y' @@ -330,13 +368,26 @@ def input_yes(*args, **kwargs): if __name__ == '__main__': parser = argparse.ArgumentParser() # positional arguments - parser.add_argument("chroot_directory", metavar="CHROOT_DIRECTORY", help="The location of the chroot to be created") - parser.add_argument("chroot_type", metavar="CHROOT_TYPE", help="A list of .lst files to use for generating the chroot", nargs="*") + parser.add_argument("chroot_directory", metavar="CHROOT_DIRECTORY", + help="The location of the chroot to be created") + + parser.add_argument("chroot_type", metavar="CHROOT_TYPE", nargs="*", + help="A list of .lst files to use for generating the " + "chroot") # optional arguments - parser.add_argument("-g", dest='globals', nargs='*', metavar="", help="Environment variables to set when creating the chroot") - parser.add_argument("-i", dest='yum_installs', nargs='*', metavar="", help="A list of packages for yum to install in the chroot") - parser.add_argument("-y", dest='auto_yes', action='store_true', help="Automatically answer yes to input prompts") - parser.add_argument("-v", dest='verbose', action='store_true', help="Print verbose output when running") + parser.add_argument("-g", dest='globals', nargs='*', metavar="", + help="Environment variables to set when creating the " + "chroot") + + parser.add_argument("-i", dest='yum_installs', nargs='*', metavar="", + help="A list of packages for yum to install in the " + "chroot") + + parser.add_argument("-y", dest='auto_yes', action='store_true', + help="Automatically answer yes to input prompts") + + parser.add_argument("-v", dest='verbose', action='store_true', + help="Print verbose output when running") args = parser.parse_args() parser.parse_args() @@ -346,7 +397,6 @@ if __name__ == '__main__': print(SCRIPT_DIR) - auto_yes = args.auto_yes initial_check() # This is done because the arg may be a relative path name. @@ -354,9 +404,9 @@ if __name__ == '__main__': TEMP_DIR = os.path.realpath(args.chroot_directory) print(TEMP_DIR) - # if -v was passed, need to turn logging to DEBUG so all logging messages in the - # code are printed - if (args.verbose): + # if -v was passed, need to turn logging to DEBUG so all logging messages + # in the code are printed + if args.verbose: logging.basicConfig(level=logging.DEBUG) logging.debug(f"Script directory: {SCRIPT_DIR}") @@ -365,7 +415,7 @@ if __name__ == '__main__': if not TEMP_DIR.startswith('/QOpenSys/'): print("\nERROR: [CHROOT DIRECTORY] Must begin with /QOpenSys/...\n") - parser.print_help + parser.print_help() sys.exit(-2) CHROOT_DIR = TEMP_DIR @@ -379,9 +429,9 @@ if __name__ == '__main__': input = input_yes print(f"{CHROOT_DIR} directory already exists") - val = input("Would you like to continue chroot setup? [y/N]: ") + USER_INPUT = input("Would you like to continue chroot setup? [y/N]: ") - if not val == "y": + if USER_INPUT != "y": print("Bye") sys.exit(-4) @@ -395,10 +445,11 @@ if __name__ == '__main__': if args.auto_yes: input = input_yes - val = input(f"Would you like to create a minimal chroot w/ includes @ {CHROOT_DIR}? [y/N]: ") - if not val == "y": + USER_INPUT = input("Would you like to create a minimal chroot w/ " + f"includes @ {CHROOT_DIR}? [y/N]: ") + if USER_INPUT != "y": print("Specify your desired [CHROOT TYPE]") - parser.print_help + parser.print_help() sys.exit(-5) mylist.append(f"{SCRIPT_DIR}/chroot_includes.lst") @@ -425,8 +476,7 @@ if __name__ == '__main__': logging.debug(f"Number of elements in the list: {len(mylist)}") logging.debug(f"List contents: {mylist}") - # convert any global variables passed from a list of string "KEY=VALUE" to a - # dictionary holding "KEY": "VALUE" + # convert global variables list of "key=value" into a dictionary globals_dictionary = {} if args.globals: for global_var in args.globals: @@ -456,12 +506,11 @@ if __name__ == '__main__': yum_install(args.yum_installs) print(f""" +Done creating your chroot! - Done creating your chroot! - - To enter your chroot - Run: chroot {args.chroot_directory} /QOpenSys/usr/bin/sh +To enter your chroot +Run: chroot {args.chroot_directory} /QOpenSys/usr/bin/sh - To set up your PATH to pick up RPM packages once inside your chroot - Run: . /QOpenSys/etc/profile - """) +To set up your PATH to pick up RPM packages once inside your chroot +Run: . /QOpenSys/etc/profile +""")