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