Skip to content

Commit

Permalink
feat(device): handles failed hwil devices during apply and delete
Browse files Browse the repository at this point in the history
  • Loading branch information
pallabpain committed Dec 5, 2024
1 parent d590490 commit 94bb48e
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 50 deletions.
9 changes: 7 additions & 2 deletions riocli/device/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def apply(self, *args, **kwargs) -> ApplyResult:

# Create the HWIL (virtual) device and then generate the labels
# to store HWIL metadata in rapyuta.io device.
hwil_response = create_hwil_device(self.spec, self.metadata)
hwil_response = create_hwil_device(virtual, self.metadata)
labels = make_device_labels_from_hwil_device(hwil_response)

# Create the rapyuta.io device with labels if the
Expand Down Expand Up @@ -100,10 +100,15 @@ def delete(self, *args, **kwargs) -> None:
try:
device = find_device_by_name(client, self.metadata.name)
except DeviceNotFound:
# If it was a virtual device, try deleting the HWIL
# resource if it is present and raise ResourceNotFound.
if self.spec.get("virtual", {}).get("enabled", False):
delete_hwil_device(self.spec.virtual, self.metadata)

raise ResourceNotFound

if self.spec.get("virtual", {}).get("enabled", False):
delete_hwil_device(device)
delete_hwil_device(self.spec.virtual, self.metadata)

device.delete()

Expand Down
106 changes: 60 additions & 46 deletions riocli/device/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,26 +226,63 @@ def is_remote_path(src, devices=None):
return None, src


def sanitize_hwil_device_name(name: str) -> str:
if len(name) == 0:
return name

name = name[0:50]
name = trim_suffix(name)
name = trim_prefix(name)

r = ""
for c in name:
if c.isalnum() or c in ["-", "_"]:
r = r + c

return r


def generate_hwil_device_name(
name: str,
product: str,
user: str,
project_id: str,
) -> str:
"""Generates a valid hardware-in-the-loop device name."""
project = project_id.split("project-")[1]
return sanitize_hwil_device_name(f"{name}-{product}-{user}-{project}")


def create_hwil_device(spec: dict, metadata: dict) -> Munch:
"""Create a new hardware-in-the-loop device."""
virtual = spec["virtual"]
os = virtual["os"]
codename = virtual["codename"]
arch = virtual["arch"]
product = virtual["product"]
os = spec["os"]
codename = spec["codename"]
arch = spec["arch"]
product = spec["product"]
name = metadata["name"]

labels = make_hwil_labels(virtual, name)
device_name = sanitize_hwil_device_name(f"{name}-{product}-{labels['user']}")
labels = make_hwil_labels(spec, name)
device_name = generate_hwil_device_name(
name, product, labels["user"], labels["project"]
)

client = new_hwil_client()
device = None

try:
device_id = find_device_id(client, device_name)
return client.get_device(device_id)
device = client.get_device(device_id)
if device and device.status != "FAILED":
return device
except DeviceNotFound:
pass # Do nothing and proceed.

if device and device.status == "FAILED":
try:
client.delete_device(device.id)
except Exception:
raise Exception("cannot delete previously failed device")

response = client.create_device(device_name, arch, os, codename, labels)
client.poll_till_device_ready(response.id, sleep_interval=5, retry_limit=12)

Expand All @@ -255,28 +292,21 @@ def create_hwil_device(spec: dict, metadata: dict) -> Munch:
return response


def delete_hwil_device(device: Device) -> None:
"""Delete a hardware-in-the-loop device.
This is a helper method that deletes a HWIL device
associated with the rapyuta.io device.
"""
labels = device.get("labels", {})
if not labels:
raise DeviceNotFound(message="hwil device not found")

device_id = None

for label in labels:
if label["key"] == "hwil_device_id":
device_id = label["value"]
break

if device_id is None:
raise DeviceNotFound(message="hwil device not found")
def delete_hwil_device(spec: dict, metadata: dict) -> None:
"""Delete a hardware-in-the-loop device by name."""
product = spec["product"]
name = metadata["name"]
labels = make_hwil_labels(spec, name)
device_name = generate_hwil_device_name(
name, product, labels["user"], labels["project"]
)

client = new_hwil_client()
client.delete_device(device_id)
devices = client.list_devices(query={"name": device_name})
if not devices:
return

client.delete_device(devices[0].id)


def execute_onboard_command(device_id: int, onboard_command: str) -> None:
Expand Down Expand Up @@ -312,30 +342,14 @@ def make_hwil_labels(spec: dict, device_name: str) -> typing.Dict:

def make_device_labels_from_hwil_device(d: Munch) -> dict:
return {
"hwil_device_id": str(d.id),
"hwil_device_name": d.name,
"arch": d.architecture,
"flavor": d.flavor,
"hwil_device_id": str(d.id),
"hwil_device_name": d.name,
"hwil_device_username": d.username,
}


def sanitize_hwil_device_name(name):
if len(name) == 0:
return name

name = name[0:50]
name = trim_suffix(name)
name = trim_prefix(name)

r = ""
for c in name:
if c.isalnum() or c in ["-", "_"]:
r = r + c

return r


def wait_until_online(device: Device, timeout: int = 600) -> None:
"""Wait until the device is online.
Expand Down
10 changes: 8 additions & 2 deletions riocli/hwilclient/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,11 +212,17 @@ def poll_till_device_ready(
msg = f"Retries exhausted: Tried {retry_limit} times with {sleep_interval}s interval."
raise RetriesExhausted(msg)

def list_devices(self: Client):
def list_devices(self: Client, query: dict = None) -> Munch:
"""Fetch all HWIL devices"""
url = f"{self._host}/device/"
headers = self._get_auth_header()
response = RestClient(url).method(HttpMethod.GET).headers(headers).execute()
response = (
RestClient(url)
.method(HttpMethod.GET)
.headers(headers)
.query_param(query or {})
.execute()
)
handle_server_errors(response)

data = json.loads(response.text)
Expand Down

0 comments on commit 94bb48e

Please sign in to comment.