def run()

in src/vm-repair/azext_vm_repair/custom.py [0:0]


def run(cmd, vm_name, resource_group_name, run_id=None, repair_vm_id=None, custom_script_file=None, parameters=None, run_on_repair=False, preview=None):  
  
    # Log the input parameters for the method  
    logger.debug('vm repair run parameters: vm_name: %s, resource_group_name: %s, run_id: %s, repair_vm_id: %s, custom_script_file: %s, parameters: %s, run_on_repair: %s, preview: %s',  
                 vm_name, resource_group_name, run_id, repair_vm_id, custom_script_file, parameters, run_on_repair, preview)  
  
    # Initiate a command helper object for logging and status tracking  
    command = command_helper(logger, cmd, 'vm repair run')  
  
    # Define the script names for Linux and Windows  
    LINUX_RUN_SCRIPT_NAME = 'linux-run-driver.sh'  
    WINDOWS_RUN_SCRIPT_NAME = 'win-run-driver.ps1'  
  
    # Set the repair map URL if a preview is available  
    if preview:  
        _set_repair_map_url(preview)  
  
    try:  
        # Fetch data of the VM on which the script is to be run  
        source_vm = get_vm(cmd, resource_group_name, vm_name)  
  
        # Determine the OS of the source VM  
        is_linux = _is_linux_os(source_vm)  
  
        # Choose the appropriate script based on the OS of the source VM  
        if is_linux:  
            script_name = LINUX_RUN_SCRIPT_NAME  
        else:  
            script_name = WINDOWS_RUN_SCRIPT_NAME  
  
        # If run_on_repair is False, then the repair VM is the same as the source VM (i.e., scripts run directly on the source VM)  
        if run_on_repair:  
            repair_vm_id = parse_resource_id(repair_vm_id)  
            repair_vm_name = repair_vm_id['name']  
            repair_resource_group = repair_vm_id['resource_group']  
        else:  
            repair_vm_name = vm_name  
            repair_resource_group = resource_group_name  
  
        run_command_params = []  
        additional_scripts = []  
  
        # For the default scenario where a run ID is provided  
        if not custom_script_file:  
            # Fetch the path to the script from GitHub using the run ID  
            repair_script_path = _fetch_run_script_path(run_id)  
            run_command_params.append('script_path="./{}"'.format(repair_script_path))  
        # For the custom script scenario for script testers  
        else:  
            run_command_params.append('script_path=no-op')  
            additional_scripts.append(custom_script_file)  
  
        # If a preview URL is provided, validate it and extract the fork and branch names  
        if preview:  
            parts = preview.split('/')  
            if len(parts) < 7 or parts.index('map.json') == -1:  
                raise Exception('Invalid preview url. Write full URL of map.json file. example https://github.com/Azure/repair-script-library/blob/main/map.json')  
            last_index = parts.index('map.json')  
            fork_name = parts[last_index - 4]  
            branch_name = parts[last_index - 1]  
            run_command_params.append('repo_fork="{}"'.format(fork_name))  
            run_command_params.append('repo_branch="{}"'.format(branch_name))  
  
        # Append parameters for the script  
        if parameters:  
            if is_linux:  
                param_string = _process_bash_parameters(parameters)  
            else:  
                param_string = _process_ps_parameters(parameters)  
            run_command_params.append('params="{}"'.format(param_string))  
  
        if run_on_repair:  
            vm_string = 'repair VM'  
        else:  
            vm_string = 'VM'  
  
        logger.info('Running script on %s: %s', vm_string, repair_vm_name)  # Log the VM on which the script is being run  


                # Start the timer to measure the run-time of the script  
        script_start_time = timeit.default_timer()  
  
        # Invoke the run command on the VM and capture the standard output and error  
        stdout, stderr = _invoke_run_command(script_name, repair_vm_name, repair_resource_group, is_linux, run_command_params, additional_scripts)  
  
        # Calculate the run-time of the script and log it  
        command.script.run_time = timeit.default_timer() - script_start_time  
        logger.debug("stderr: %s", stderr)  
  
        # Parse the standard output to check if the script execution was successful  
        run_script_succeeded = _check_script_succeeded(stdout)  
  
        # Parse the raw logs from the standard output  
        logs = _parse_run_script_raw_logs(stdout)  
  
        # Process the start and end of the log  
        # If the log is over 4k bytes, it gets cutoff at the start  
        log_cutoff = True  
        log_fullpath = ''  
        for log in logs:  
            if log['level'] == 'Log-Start':  
                log_cutoff = False  
            if log['level'] == 'Log-End':  
                split_log = log['message'].split(']')  
                if len(split_log) == 2:  
                    log_fullpath = split_log[1]  
  
        # If the log is cutoff, give a warning to the user  
        if log_cutoff:  
            logger.warning('Log file is too large and has been cutoff at the start of file. Please locate the log file within the %s using the logFullpath to check full logs.', vm_string)  
  
        # If the script execution was successful, set the status to success and log the output  
        # If the script execution was unsuccessful, set the status to error and log the error  
        if run_script_succeeded:  
            command.script.set_status_success()  
            command.message = 'Script completed succesfully.'  
            command.script.output = '\n'.join([log['message'] for log in logs if log['level'].lower() == 'output'])  
            logger.info('\nScript returned with output:\n%s\n', command.script.output)  
        else:  
            command.script.set_status_error()  
            command.message = 'Script completed with errors.'  
            command.script.output = '\n'.join([log['message'] for log in logs if log['level'].lower() == 'error'])  
            logger.error('\nScript returned with error:\n%s\n', command.script.output)  
  
        # Set the overall command status to success  
        command.set_status_success()  


    except KeyboardInterrupt:
        command.error_stack_trace = traceback.format_exc()
        command.error_message = "Command interrupted by user input."
        command.message = "Repair run failed. Command interrupted by user input."
    except AzCommandError as azCommandError:
        command.error_stack_trace = traceback.format_exc()
        command.error_message = str(azCommandError)
        command.message = "Repair run failed."
    except requests.exceptions.RequestException as exception:
        command.error_stack_trace = traceback.format_exc()
        command.error_message = str(exception)
        command.message = "Failed to fetch run script data from GitHub. Please check this repository is reachable: https://github.com/Azure/repair-script-library"
    except RunScriptNotFoundForIdError as exception:
        command.error_stack_trace = traceback.format_exc()
        command.error_message = str(exception)
        command.message = "Repair run failed. Run ID not found."
    except Exception as exception:
        command.error_stack_trace = traceback.format_exc()
        command.error_message = str(exception)
        command.message = 'An unexpected error occurred. Try running again with the --debug flag to debug.'
    finally:
        if command.error_stack_trace:
            logger.debug(command.error_stack_trace)

    if not command.is_status_success():
        command.set_status_error()
        command.script.output = 'Repair run failed.'
        return_dict = command.init_return_dict()
    else:
        # Build return Dict
        return_dict = command.init_return_dict()
        return_dict['script_status'] = command.script.status
        return_dict['logs'] = stdout
        return_dict['err'] = stderr
        return_dict['log_full_path'] = log_fullpath
        return_dict['output'] = command.script.output
        return_dict['vm_name'] = repair_vm_name
        return_dict['resource_group'] = repair_resource_group

    return return_dict