diff --git a/.github/workflows/canary_ota.yml b/.github/workflows/canary_ota.yml index 606b6577a..f6e62c9ff 100644 --- a/.github/workflows/canary_ota.yml +++ b/.github/workflows/canary_ota.yml @@ -6,11 +6,8 @@ on: otaTag: description: 'OtaService Config Version tag' required: true - type: choice - default: 'latest' - options: - - latest - - v0.4.0 # earlier versions do not support OTA + type: string + default: "testing" env: ESP32_CANARY_ROBOT: ${{ secrets.ESP32_CANARY_ROBOT }} diff --git a/canary/canary_ota.py b/canary/canary_ota.py index 0d4b87ec6..be66ebd5e 100644 --- a/canary/canary_ota.py +++ b/canary/canary_ota.py @@ -1,45 +1,47 @@ import asyncio import time +import datetime import copy import os +import slack_sdk +import slack_sdk.errors +from dateutil import tz + from viam.robot.client import DialOptions from viam.app.viam_client import ViamClient -async def connect(robot_address: str, api_key: str, api_key_id: str) -> ViamClient: - dial_options = DialOptions.with_api_key(api_key_id=api_key_id,api_key=api_key) - return await ViamClient.create_from_dial_options(dial_options) -async def main(): +async def connect(api_key: str, api_key_id: str, num_attempts: int) -> ViamClient: + for i in range(num_attempts): + try: + dial_options = DialOptions.with_api_key(api_key_id=api_key_id, api_key=api_key) + viam_client = await ViamClient.create_from_dial_options(dial_options) + return viam_client + except Exception as e: + if i == num_attempts-1: + raise e + print(e) + time.sleep(0.5) - robot_address = os.environ["ESP32_CANARY_ROBOT"] +async def main(): api_key = os.environ["ESP32_CANARY_API_KEY"] api_key_id = os.environ["ESP32_CANARY_API_KEY_ID"] part_id = os.environ["ESP32_CANARY_ROBOT_PART_ID"] tag_name = os.environ["ESP32_CANARY_OTA_VERSION_TAG"] - - bin_name = "micro-rdk-server-esp32-ota.bin" - url_base = "https://github.com/viamrobotics/micro-rdk/releases" + bucket_url = os.environ["GCP_BUCKET_URL"] + bucket_name = os.environ["GCP_BUCKET_NAME"] + bin_name = os.environ["ESP32_OTA_BINARY_NAME"] - if tag_name == "latest": - url_target = f"{url_base}/latest/download/{bin_name}" - else: - url_target = f"{url_base}/download/{tag_name}/{bin_name}" + url = f"{bucket_url}/{bucket_name}/{tag_name}/{bin_name}" - print(f"connecting to robot at {robot_address} ...") - - for i in range(5): - try: - viam_client = await connect(robot_address, api_key, api_key_id) - break - except Exception as e: - if i == 4: - raise e - print(e) - time.sleep(0.5) + print(f"connecting ViamClient ...") + + viam_client = await connect(api_key, api_key_id, 5) cloud = viam_client.app_client + print(f"getting robot part...") robot_part = await cloud.get_robot_part(robot_part_id=part_id) service_updated = False @@ -47,31 +49,53 @@ async def main(): for service in updated_config["services"]: # assumes only one such service exists if service["model"] == "ota_service": - service["attributes"]["url"] = url_target + service["attributes"]["url"] = url service["attributes"]["version"] = tag_name service_updated = True - print(f"updating OtaServiceConfig to `{service}`") + print(f"updating OtaServiceConfig version to `{tag_name}`") break if not service_updated: viam_client.close() - raise Exception("failed to find or update ota service config") + msg = f"failed to find or update ota service config to `{tag_name}`" + post_to_slack(msg, True) + raise Exception(msg) + print("updating robot part config...") await cloud.update_robot_part( robot_part_id=robot_part.id, name=robot_part.name, robot_config=updated_config ) - # retrieve new config to verify + print("verifying config change...") robot_part = await cloud.get_robot_part(robot_part_id=part_id) for service in robot_part.robot_config["services"]: if service["model"] == "ota_service": print(f"OtaServiceConfig after updating: `{service}`") - if service["attributes"]["url"] != url_target or service["attributes"]["version"] != tag_name: - raise Exception("ota service config does not reflect update") + if service["attributes"]["url"] != url or service["attributes"]["version"] != tag_name: + msg = f"ota service config does not reflect update to `{tag_name}`" + post_to_slack(msg, True) + raise Exception(msg) viam_client.close() + post_to_slack(f"OtaService config successfully updated to `{tag_name}`", False) + +def post_to_slack(msg: str, is_error: bool): + today = datetime.datetime.now(tz=tz.UTC).date() + msg = f"{today}: {msg}" + slack_token = os.environ["CANARY_SLACKBOT_TOKEN"] + channel_id = os.environ["MICRO_RDK_TEAM_CHANNEL_ID"] + client = slack_sdk.WebClient(token=slack_token) + api_result = client.chat_postMessage(channel=channel_id, text=msg) + + try: + api_result.validate() + if is_error: + raise Exception(msg) + except Exception as e: + raise Exception(f"failure to post to Slack, error message was '{msg}'") from e + if __name__ == '__main__': asyncio.run(main())