Bruno Muniz 07051a09aa Remove all hard-coded passwords and require it
- Additionally, add password validation function.
- Breaks Parser.py into more manageable functions.
- Changes where defaults are set (Parser.py instead of class under
/consts)

The goal is to not have any reference to a password in the code
itself, only in configuration files or README files, if strictly
necessary.

The new password validation function, besides failing fast at the
argument parser, makes sure the password will be allowed by Debian
later on the installation.

This commit is not touching any Shell script because they will
probably be removed or change in follow-up commits.

Test Plan:
PASS: Operating system password should be set to value passed via
--password

Failure Path:
PASS: Script fails fast without the parameter --password
PASS: Script fails fast if password requirements are not met

Regression:
PASS: AIO-SX install works

Story: 2005051
Task: 47960
Task: 48230

Change-Id: Ibf42b792ef825cee61cc69d1b5afa807361037b7
Signed-off-by: Bruno Muniz <bruno.muniz@encora.com>
2023-06-30 14:28:02 -03:00

448 lines
18 KiB
Python

# 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)
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("--username", help=
"""
Username. default is 'sysadmin'
""",
type=str,
default="sysadmin")
parser.add_argument("--password", help=
"""
Password.
""",
type=validate_password,
required=True)
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)
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("--config-controller-ini", help=
"""
Path to the local config_controller .ini. This
file is transferred to the controller. NOTE: OAM
configuration in this ini is updated dynamically
based on networking related args.
(e.g. stx_config.ini_centos,
~/stx_config.ini_centos, /home/myousaf ...).
""",
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.
""",
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')
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). This is also used to
update GATEWAY_IP in [OAM_NETWORK] of config_controller config file.
""",
type=str)
parser.add_argument("--add-nat-interface", help=
"""
Add a new NAT interface to hosts.
""",
action='store_true')
parser.add_argument("--controller-floating-ip", help=
"""
OAM floating IP.
""",
type=str,
default="10.10.10.5")
parser.add_argument("--controller0-ip", help=
"""
OAM IP of controller-0. This is also used to
update IP_ADDRESS in [OAM_NETWORK] of
config_controller config file of an AIO SX setup.
This should not be the floating IP.
""",
type=str,
default="10.10.10.3")
parser.add_argument("--controller1-ip", help=
"""
OAM IP of controller-1.
This should not be the floating IP.
""",
type=str,
default="10.10.10.4")
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-controller-floating-local-ssh-port", help=
"""
When oam network is configured as 'nat' a port on
the vbox host is used for connecting to ssh on
floating controller. No default value is
configured. This is mandatory if --vboxnet-type is
'nat' for non AIO-SX deployments.
""",
type=str)
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("--ini-oam-cidr", help=
"""
The IP network and mask for the oam net, used to
update CIDR value in [OAM_NETWORK] of
config_controller config file. Default is
10.10.10.0/24
""",
type=str)
parser.add_argument("--ini-oam-ip-start-address", help=
"""
The start for the oam net allocation, used to
update IP_START_ADDRESS value in [OAM_NETWORK] of
config_controller config file. Not needed for AIO
SX setups.
""",
type=str)
parser.add_argument("--ini-oam-ip-end-address", help=
"""
The end for the oam net allocation, used to update
IP_END_ADDRESS value in [OAM_NETWORK] of
config_controller config file. Not needed for AIO
SX setups.
""",
type=str)
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:
<script_name>,<timeout>,<serial or ssh>,<user/root> 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 <script_name);
Script executes successfully if return code is 0. Anything else
is considered error and further execution is aborted.
""",
default=None,
type=str)
parser.add_argument("--script2", help=
"""
See --script1
""",
default=None,
type=str)
parser.add_argument("--script3", help=
"""
See --script1
""",
default=None,
type=str)
parser.add_argument("--script4", help=
"""
See --script1
""",
default=None,
type=str)
parser.add_argument("--script5", help=
"""
See --script1
""",
default=None,
type=str)
def parse_other(parser: ArgumentParser):
"""
Mutate parser with CLI arguments related to overall flow control
"""
parser.add_argument("--list-stages", help=
"""
List stages that can be used by autoinstaller.
""",
action='store_true')
parser.add_argument("--logpath", help=
"""
Base directory to store logs.
""",
type=str)
parser.add_argument("--force-delete-lab", help=
"""
Don't ask for confirmation when deleting a lab.
""",
action='store_true')
parser.add_argument("--snapshot", help=
"""
Take snapshot at different stages when the lab is installed.
E.g. before and after config_controller, before and after lab_setup.
""",
action='store_true')
parser.add_argument("--securityprofile", help=
"""
Security profile to use:
standard
extended
Standard is the default
""",
type=str, choices=['standard', 'extended'],
default='standard')
parser.add_argument("--labname", help=
"""
The name of the lab to be created.
""",
type=str)
parser.add_argument("--userid", help=
"""
Unique user id to differentiate vbox machine
unique names such as interface names or serial
ports even if setups have the same names for
different users. Default is your username on this
machine.
""",
type=str,
default=getpass.getuser())
parser.add_argument("--hostiocache", help=
"""
Turn on host i/o caching
""",
action='store_true')