def parse_args(): """Parse and return command line arguments, validate the host.""" parser = lib.get_base_parser('Automated reimaging of a single host') parser.add_argument( '--rename', help='FQDN of the new name to rename this host to while reimaging') parser.add_argument( '--rename-mgmt', help='FQDN of the new name management interface, see --rename') parser.add_argument('host', metavar='HOST', action='store', help='FQDN of the host to be reimaged') parser.add_argument('mgmt', metavar='MGMT', action='store', nargs='?', default=None, help='FQDN of the management interface for the host') args = parser.parse_args() fqdns = [args.host] if args.rename is not None: fqdns.append(args.rename) if args.no_pxe: raise argparse.ArgumentTypeError( 'The --rename option cannot be used in conjunction with --no-pxe.' ) # Gather the management interfaces, if missing if args.mgmt is None: mgmts = lib.get_mgmts([args.host]) args.mgmt = mgmts[args.host] else: mgmts = {args.host: args.mgmt} fqdns.append(args.mgmt) if args.rename is not None and args.rename_mgmt is None: mgmts.update(lib.get_mgmts([args.rename])) fqdns.append(mgmts[args.rename]) # Perform a quick sanity check on the host and mgmt for name in fqdns: if '.' not in name or not lib.HOSTS_PATTERN.match(name): raise argparse.ArgumentTypeError( "Expected FQDN, got '{name}'".format(name=name)) if not lib.is_hostname_valid(name): raise argparse.ArgumentTypeError( "Unable to resolve host '{name}'".format(name=name)) for mgmt in mgmts.values(): if '.mgmt.' not in mgmt: raise argparse.ArgumentTypeError( 'The MGMT parameter {} does not follow the *.mgmt.* format'. format(mgmt)) return args
def run(args, user, log_path): """Run the reimage for all the hosts in subproceesses.""" # Setup phab_client = lib.get_phabricator_client() lib.ensure_ipmi_password() mgmts = lib.get_mgmts(args.hosts) # Check that IPMI is working for all the hosts for host in args.hosts: lib.check_remote_ipmi(mgmts[host]) # Initialize data structures procs = {} retcodes = defaultdict(list) # Validate hosts if not args.new: lib.validate_hosts(args.hosts, no_raise=args.no_verify) # Update the Phabricator task if args.phab_task_id is not None: lib.phabricator_task_update( phab_client, args.phab_task_id, lib.PHAB_COMMENT_PRE.format(user=user, hostname=socket.getfqdn(), hosts=args.hosts, log=log_path)) # Run the reimage for each host in a child process try: for host in args.hosts: proc = reimage_host(host, mgmts[host], args) if args.sequential: retcodes[host] = proc.wait() time.sleep(args.sleep) else: procs[host] = proc if procs: retcodes = wait_for_childrens(procs) except KeyboardInterrupt: # Terminate childrens if procs: for process in procs: process.terminate() else: proc.terminate() raise # Comment on the Phabricator task if args.phab_task_id is not None: phabricator_message = lib.get_phabricator_post_message(retcodes) lib.phabricator_task_update(phab_client, args.phab_task_id, phabricator_message) if max(retcodes.keys()) > 0: return 1 return 0
def main(): """Run the script.""" script_name = os.path.basename(__file__) args = parse_args() user = lib.get_running_user() phab_client = lib.get_phabricator_client() is_valid_host = lib.is_hostname_valid(args.host) actions = [] if not is_valid_host and not args.force: logger.error( "{host} is not a valid hostname. Aborting.".format(host=args.host)) return 1 # Remove from Puppet and PuppetDB lib.puppet_remove_host(args.host) actions += ['Revoked Puppet certificate', 'Removed from PuppetDB'] # Downtime on Icinga both the host and the mgmt host, they will be removed by Puppet if is_valid_host: try: lib.icinga_downtime(args.host, user, args.phab_task_id, title=script_name) actions.append('Downtimed host on Icinga') except RuntimeError: actions.append( 'Skipped downtime host on Icinga (likely already removed)') mgmts = lib.get_mgmts([args.host]) try: lib.icinga_downtime(mgmts[args.host], user, args.phab_task_id, title=script_name) actions.append('Downtimed mgmt interface on Icinga') except RuntimeError: actions.append( 'Skipped downtime mgmt interface on Icinga (likely already removed)' ) # Remove from DebMonitor lib.debmonitor_remove_host(args.host) actions.append('Removed from DebMonitor') message = ( '{script} was executed by {user} for {host} and performed the following actions:\n' '- {actions}').format(script=script_name, user=user, host=args.host, actions='\n- '.join(actions)) lib.phabricator_task_update(phab_client, args.phab_task_id, message) return 0