# pylint: disable=invalid-name #!/usr/bin/python3 # # SPDX-License-Identifier: Apache-2.0 # """ Parser to handle command line arguments """ import argparse import re from argparse import ArgumentParser, RawTextHelpFormatter import getpass def validate_password(pwd: str): """ Validation function that raises an argparse.ArgumentTypeError if requirements are not met. Args: pwd: the password to validate against requirements Returns: the password, if requirements are met """ errors = [ None if len(pwd) >= 7 else "at least 7 characters long", None if re.search(r'[!@#$%^&*(),.?":{}|<>]', pwd) else "at least one special character", None if any(c.isupper() for c in pwd) else "at least one capital letter", None if any(c.isdigit() for c in pwd) else "at least one digit" ] errors = list(filter(None, errors)) # Remove occurrences of None from errors list if errors: raise argparse.ArgumentTypeError(f'unmet requirements: {"; ".join(errors)}') return pwd def handle_args(): """ Handle arguments supplied via command line """ parser = ArgumentParser(formatter_class=RawTextHelpFormatter) parse_setup_config(parser) parse_config_location(parser) parse_disk_info(parser) parse_networking(parser) parse_custom_scripts(parser) parse_other(parser) return parser def parse_setup_config(parser: ArgumentParser): """ Mutate parser with CLI arguments related to the setup type """ parser.add_argument("--setup-type", help= """ Type of setup: AIO-SX AIO-DX STANDARD STORAGE """, choices=['AIO-SX', 'AIO-DX', 'STANDARD', 'STORAGE'], type=str, required=True) parser.add_argument("--controllers", help= """ Number of controllers: 1 - single controller 2 - two controllers """, choices=[1, 2], type=int, default=2) parser.add_argument("--workers", help= """ Number of workers: 1 - single worker 2 - two workers etc. """, type=int, default=2) parser.add_argument("--storages", help= """ Number of storage nodes: 1 - single storage node 2 - two storage nodes etc.\n """, type=int, default=2) parser.add_argument("--from-stage", help= """ Start stage. For a list of stages run --list-stages \n """, type=str) parser.add_argument("--to-stage", help= """ End stage. For a list of stages run --list-stages \n """, type=str) parser.add_argument("--custom-stages", help= """ Custom, comma separated list of stages. For a list of stages run --list-stages \n """, type=str, default=None) parser.add_argument("--lowlatency", help= """ Whether to install an AIO system as low latency. """, action='store_true') parser.add_argument("--install-mode", help= """ Lab will be installed using the mode specified. Serial mode by default """, type=str, choices=['serial', 'graphical'], default='serial') parser.add_argument("--password", help= """ admin password """, type=validate_password, required=True) parser.add_argument("--sysadmin-password", help= """ sysadmin password This argument is optional The default value is the admin password """, type=validate_password) def parse_config_location(parser: ArgumentParser): """ Mutate parser with CLI arguments related with the location of files and configuration """ parser.add_argument("--iso-location", help= """ Location of ISO including the filename: /folk/myousaf/bootimage.ISO """, type=str, required=True) parser.add_argument("--config-files-dir", help= """ Directory with config files, scripts, images (i.e. lab_setup.sh, lab_setup.conf, ...) that are needed for the install. All files at this location are transfered to controller-0 in /home/sysadmin. You can add you own scripts that you need to be present on the controller. Caution: rsync will follow links and will fail if links are broken! Use --config-files-dir-dont-follow-links instead. Also, you can use both options for different folders. """, type=str) parser.add_argument("--config-files-dir-dont-follow-links", help= """ Same as --config-files-dir but keep symbolic link as is. """, type=str) parser.add_argument("--ansible-controller-config", help= """ Path to a local YAML file to be copied as localhost.yml to the home directory of the controller-0. NOTE: System password value is updated dynamically with user defined --password. """, type=str) parser.add_argument("--vbox-home-dir", help= """ This is the folder where vbox disks will be placed. e.g. /home or /folk/cgts/users The disks will be in /home/wzhou/vbox_disks/ or /folk/cgts/users/wzhou/vbox_disks/ """, type=str, default='/home') parser.add_argument("--lab-setup-conf", help= """ Path to the config file to use """, action='append') parser.add_argument("--kubernetes-config-files", help= """ Path to a local YAML files (admin-login.yaml and dashboard-values.yml) that will be copied to the home directory of the controller-0 for the kubernetes dashboard instalation and configuration. """, type=str) parser.add_argument("--openstack-package-location", help= """ Path to stx-openstack package location """, type=str, default=None) def parse_disk_info(parser: ArgumentParser): """ Mutate parser with CLI arguments related with VirtualBox disks arguments """ parser.add_argument("--controller-disks", help= """ Select the number of disks for a controller VM. default is 3 """, type=int, default=3, choices=[1, 2, 3, 4, 5, 6, 7]) parser.add_argument("--storage-disks", help= """ Select the number of disks for storage VM. default is 3 """, type=int, default=3, choices=[1, 2, 3, 4, 5, 6, 7]) parser.add_argument("--worker-disks", help= """ Select the number of disks for a worker VM. default is 2 """, type=int, default=2, choices=[1, 2, 3, 4, 5, 6, 7]) parser.add_argument("--controller-disk-sizes", help= """ Configure size in MiB of controller disks as a comma separated list. """, type=str) parser.add_argument("--storage-disk-sizes", help= """ Configure size in MiB of storage disks as a comma separated list. """, type=str) parser.add_argument("--worker-disk-sizes", help= """ Configure size in MiB of worker disks as a comma separated list. """, type=str) def parse_networking(parser: ArgumentParser): """ Mutate parser with CLI arguments related with VirtualBox networking """ parser.add_argument("--vboxnet-name", help= """ Which host only network to use for setup. """, type=str) parser.add_argument("--vboxnet-ip", help= """ The IP address of the host only adapter as it is configured on the host (i.e. gateway). """, type=str) parser.add_argument("--add-nat-interface", help= """ Add a new NAT interface to hosts. """, action='store_true') parser.add_argument("--vboxnet-type", help= """ Type of vbox network, either hostonly on nat """, choices=['hostonly', 'nat'], type=str, default='hostonly') parser.add_argument("--nat-controller0-local-ssh-port", help= """ When oam network is configured as 'nat' a port on the vbox host is used for connecting to ssh on controller-0. This is mandatory if --vboxnet-type is 'nat'. No default value is configured. """, type=str) parser.add_argument("--nat-controller1-local-ssh-port", help= """ When oam network is configured as 'nat' a port on the vbox host is used for connecting to ssh on controller-1. No default value is configued. This is mandatory if --vboxnet-type is 'nat' for non AIO-SX deployments or if second controller is installed. """, type=str) parser.add_argument("--nat-controller-floating-ssh-port", help= """ When oam network is configured as 'nat' a port on the vbox host is used for connecting to ssh on active controller. No default value is configued. This is mandatory if --vboxnet-type is 'nat' for non AIO-SX deployments or if second controller is installed. """, type=str) parser.add_argument("--horizon-dashboard-port", help= """ Port for the visualization of the StarlingX Horizon dashboard. If no port value is set, it defaults to port 8080 """, type=str, default='8080') parser.add_argument("--kubernetes-dashboard-port", help= """ Port for the visualization of the kubernetes dashboard. If no port value is set, it default to port 32000 """, type=str, default='32000') parser.add_argument("-y", "--yes-to-all", dest="y", help= """ Automatically answers all yes/no prompts with yes. """, action='store_true') def parse_custom_scripts(parser: ArgumentParser): """ Mutate parser with CLI arguments related to custom scripts """ parser.add_argument("--script1", help= """ Name of an executable script file plus options. Has to be present in --config-files-dir. It will be transfered to host in rsync-config stage and executed as part of custom-script1 stage. Example: --script1 'scripts/k8s_pv_cfg.sh,50,ssh,user' Contains a comma separated value of: ,,, Where: script_name = name of the script, either .sh or .py; timeout = how much to wait, in seconds, before considering failure; serial/ssh = executed on the serial console; user/root = as a user or as root (sudo