Skip to content

Commit

Permalink
feat(abr-testing): pull protocol from failing robot (#17125)
Browse files Browse the repository at this point in the history
Added feature to pull python protocol file from specifed robot with run
error, as well as additional error handling
# Overview

Pulls python protocol file from robot with error and attaches to JIRA
ticket.

## Test Plan and Hands on Testing

Tested manually
  • Loading branch information
AnthonyNASC20 authored Dec 18, 2024
1 parent 2084121 commit c24cdfb
Showing 1 changed file with 63 additions and 10 deletions.
73 changes: 63 additions & 10 deletions abr-testing/abr_testing/data_collection/abr_robot_error.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,35 @@
import sys
import json
import re
from pathlib import Path
import pandas as pd
from statistics import mean, StatisticsError
from abr_testing.tools import plate_reader


def retrieve_protocol_file(
protocol_id: str,
robot_ip: str,
storage: str,
) -> Path | str:
"""Find and copy protocol file on robot with error."""
protocol_dir = f"/var/lib/opentrons-robot-server/7.1/protocols/{protocol_id}"

print(f"FILE TO FIND: {protocol_dir}/{protocol_id}")
# Copy protocol file found in robot oto host computer
save_dir = Path(f"{storage}/protocol_errors")
command = ["scp", "-r", f"root@{robot_ip}:{protocol_dir}", save_dir]
try:
# If file found and copied return path to file
subprocess.run(command, check=True) # type: ignore
print("File transfer successful!")
return save_dir
except subprocess.CalledProcessError as e:
print(f"Error during file transfer: {e}")
# Return empty string if file can't be copied
return ""


def compare_current_trh_to_average(
robot: str,
start_time: Any,
Expand All @@ -38,9 +62,13 @@ def compare_current_trh_to_average(
# Find average conditions of errored time period
df_all_trh = pd.DataFrame(all_trh_data)
# Convert timestamps to datetime objects
df_all_trh["Timestamp"] = pd.to_datetime(
df_all_trh["Timestamp"], format="mixed", utc=True
).dt.tz_localize(None)
print(f'TIMESTAMP: {df_all_trh["Timestamp"]}')
try:
df_all_trh["Timestamp"] = pd.to_datetime(
df_all_trh["Timestamp"], format="mixed", utc=True
).dt.tz_localize(None)
except Exception:
print(f'The following timestamp is invalid: {df_all_trh["Timestamp"]}')
# Ensure start_time is timezone-naive
start_time = start_time.replace(tzinfo=None)
relevant_temp_rhs = df_all_trh[
Expand Down Expand Up @@ -245,20 +273,24 @@ def get_user_id(user_file_path: str, assignee_name: str) -> str:
return assignee_id


def get_error_runs_from_robot(ip: str) -> List[str]:
def get_error_runs_from_robot(ip: str) -> Tuple[List[str], List[str]]:
"""Get runs that have errors from robot."""
error_run_ids = []
protocol_ids = []
response = requests.get(
f"http://{ip}:31950/runs", headers={"opentrons-version": "3"}
)
run_data = response.json()
run_list = run_data.get("data", [])
for run in run_list:
run_id = run["id"]
protocol_id = run["protocolId"]
num_of_errors = len(run["errors"])
if not run["current"] and num_of_errors > 0:
error_run_ids.append(run_id)
return error_run_ids
# Protocol ID will identify the correct folder on the robot of the protocol file
protocol_ids.append(protocol_id)
return (error_run_ids, protocol_ids)


def get_robot_state(
Expand Down Expand Up @@ -335,7 +367,7 @@ def get_robot_state(


def get_run_error_info_from_robot(
ip: str, one_run: str, storage_directory: str
ip: str, one_run: str, storage_directory: str, protocol_found: bool
) -> Tuple[str, str, str, List[str], List[str], str, str]:
"""Get error information from robot to fill out ticket."""
description = dict()
Expand Down Expand Up @@ -369,6 +401,9 @@ def get_run_error_info_from_robot(
description["protocol_name"] = results["protocol"]["metadata"].get(
"protocolName", ""
)

# If Protocol was successfully retrieved from the robot
description["protocol_found_on_robot"] = protocol_found
# Get start and end time of run
start_time = datetime.strptime(
results.get("startedAt", ""), "%Y-%m-%dT%H:%M:%S.%f%z"
Expand Down Expand Up @@ -511,12 +546,21 @@ def get_run_error_info_from_robot(
users_file_path = ticket.get_jira_users(storage_directory)
assignee_id = get_user_id(users_file_path, assignee)
run_log_file_path = ""
protocol_found = False
try:
error_runs = get_error_runs_from_robot(ip)
error_runs, protocol_ids = get_error_runs_from_robot(ip)
except requests.exceptions.InvalidURL:
print("Invalid IP address.")
sys.exit()
if len(run_or_other) < 1:
# Retrieve the most recently run protocol file
protocol_files_path = retrieve_protocol_file(
protocol_ids[-1], ip, storage_directory
)
# Set protocol_found to true if python protocol was successfully copied over
if protocol_files_path:
protocol_found = True

one_run = error_runs[-1] # Most recent run with error.
(
summary,
Expand All @@ -526,7 +570,9 @@ def get_run_error_info_from_robot(
labels,
whole_description_str,
run_log_file_path,
) = get_run_error_info_from_robot(ip, one_run, storage_directory)
) = get_run_error_info_from_robot(
ip, one_run, storage_directory, protocol_found
)
else:
(
summary,
Expand Down Expand Up @@ -566,8 +612,15 @@ def get_run_error_info_from_robot(
# OPEN TICKET
issue_url = ticket.open_issue(issue_key)
# MOVE FILES TO ERROR FOLDER.
print(protocol_files_path)
error_files = [saved_file_path_calibration, run_log_file_path] + file_paths
error_folder_path = os.path.join(storage_directory, issue_key)

# Move protocol file(s) to error folder
if protocol_files_path:
for file in os.listdir(protocol_files_path):
error_files.append(os.path.join(protocol_files_path, file))

error_folder_path = os.path.join(storage_directory, "issue_key")
os.makedirs(error_folder_path, exist_ok=True)
for source_file in error_files:
try:
Expand All @@ -577,7 +630,7 @@ def get_run_error_info_from_robot(
shutil.move(source_file, destination_file)
except shutil.Error:
continue
# POST FILES TO TICKET
# POST ALL FILES TO TICKET
list_of_files = os.listdir(error_folder_path)
for file in list_of_files:
file_to_attach = os.path.join(error_folder_path, file)
Expand Down

0 comments on commit c24cdfb

Please sign in to comment.