{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Tutorial: Hello, Workload!\n",
    "\n",
    "The shortest path from zero to a running container on DataRobot. In about five minutes you'll deploy [`containous/whoami`](https://hub.docker.com/r/containous/whoami)&mdash;a tiny, publicly available third-party image (not published by DataRobot) that echoes request headers&mdash;as a **draft Workload**, hit its endpoint, and tear it down.\n",
    "\n",
    "A **draft Workload** is the hello-world equivalent for the Workload API: one `POST /workloads` call, no artifact registration ceremony, auto-cleanup after 8 hours."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7eb1a452",
   "metadata": {},
   "source": [
    "## Connect to DataRobot\n",
    "\n",
    "To connect to DataRobot, you need the following:\n",
    "\n",
    "- DataRobot API endpoint and token, `DATAROBOT_ENDPOINT` and `DATAROBOT_API_TOKEN`.\n",
    "- A terminal with `curl`. JSON responses are parsed in Python in this notebook so it runs without extra dependencies.\n",
    "\n",
    "The connection details are set automatically inside this DataRobot Notebook. The next cell connects to DataRobot and exports `DATAROBOT_ENDPOINT` / `DATAROBOT_API_TOKEN` as shell environment variables so the `curl` cells that follow can use them."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b4d775f0",
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "\n",
    "import datarobot as dr\n",
    "\n",
    "client = dr.Client()\n",
    "os.environ.setdefault(\"DATAROBOT_ENDPOINT\", client.endpoint)\n",
    "os.environ.setdefault(\"DATAROBOT_API_TOKEN\", client.token)\n",
    "\n",
    "print(\"Connected:\", os.environ[\"DATAROBOT_ENDPOINT\"])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5e481649",
   "metadata": {},
   "source": [
    "## Deploy whoami\n",
    "\n",
    "Create a Workload with an inline draft artifact&mdash;one `POST /workloads` call defines the container and creates the Workload together. `whoami` is a tiny HTTP server that echoes request information, perfect for confirming traffic flows end-to-end."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "65400cd7",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%bash\n",
    "curl -s -X POST \"${DATAROBOT_ENDPOINT}/workloads\" \\\n",
    "  -H \"Authorization: Bearer ${DATAROBOT_API_TOKEN}\" \\\n",
    "  -H \"Content-Type: application/json\" \\\n",
    "  -d '{\n",
    "    \"name\": \"hello-whoami\",\n",
    "    \"artifact\": {\n",
    "      \"name\": \"whoami-artifact\",\n",
    "      \"type\": \"service\",\n",
    "      \"spec\": {\n",
    "        \"containerGroups\": [{\n",
    "          \"name\": \"default\",\n",
    "          \"containers\": [{\n",
    "            \"name\": \"whoami\",\n",
    "            \"imageUri\": \"containous/whoami:latest\",\n",
    "            \"port\": 8080,\n",
    "            \"primary\": true,\n",
    "            \"entrypoint\": [\"/whoami\", \"--port\", \"8080\"],\n",
    "            \"readinessProbe\": {\n",
    "              \"path\": \"/\",\n",
    "              \"port\": 8080,\n",
    "              \"initialDelaySeconds\": 5\n",
    "            }\n",
    "          }]\n",
    "        }]\n",
    "      }\n",
    "    },\n",
    "    \"runtime\": {\n",
    "      \"containerGroups\": [{\n",
    "        \"name\": \"default\",\n",
    "        \"replicaCount\": 1,\n",
    "        \"containers\": [{\n",
    "          \"name\": \"whoami\",\n",
    "          \"resourceAllocation\": {\"cpu\": 1, \"memory\": \"512MB\"}\n",
    "        }]\n",
    "      }]\n",
    "    }\n",
    "  }' | tee create_output.json"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1c249bf8",
   "metadata": {},
   "source": [
    "Save the Workload ID from the response so later cells can reference it:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "dce97b0f",
   "metadata": {},
   "outputs": [],
   "source": [
    "import json\n",
    "from pathlib import Path\n",
    "\n",
    "result = json.loads(Path(\"create_output.json\").read_text())\n",
    "workload_id = result[\"id\"]\n",
    "os.environ[\"WORKLOAD_ID\"] = workload_id\n",
    "print(\"Workload ID:\", workload_id)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "557cb9fb",
   "metadata": {},
   "source": [
    "## Wait for running\n",
    "\n",
    "Poll the Workload's status until it reaches `running`. Expected happy-path progression: `submitted` &rarr; `provisioning` &rarr; `launching` &rarr; `running`. `running` requires the readiness probe to pass&mdash;the platform polls `readinessProbe.path` (here, `/`) on the container's port. If you typo the path or your container doesn't serve a 2xx on it, the Workload sits in `launching` even though the container itself is up."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0568b94b",
   "metadata": {},
   "outputs": [],
   "source": [
    "import time\n",
    "\n",
    "import requests\n",
    "\n",
    "headers = {\"Authorization\": f\"Bearer {os.environ['DATAROBOT_API_TOKEN']}\"}\n",
    "\n",
    "for i in range(120):\n",
    "    resp = requests.get(\n",
    "        f\"{os.environ['DATAROBOT_ENDPOINT']}/workloads/{workload_id}\", headers=headers\n",
    "    )\n",
    "    resp.raise_for_status()\n",
    "    status = resp.json()[\"status\"]\n",
    "    print(\"status:\", status, flush=True)\n",
    "    if status == \"running\":\n",
    "        break\n",
    "    if status == \"errored\":\n",
    "        events = requests.get(\n",
    "            f\"{os.environ['DATAROBOT_ENDPOINT']}/workloads/{workload_id}/events\", headers=headers\n",
    "        )\n",
    "        print(\"Workload errored; see the events endpoint for detail:\", events.json(), flush=True)\n",
    "        raise RuntimeError(\"Workload errored\")\n",
    "    time.sleep(5)\n",
    "else:\n",
    "    raise TimeoutError(\"Timed out waiting for running\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cba5c718",
   "metadata": {},
   "source": [
    "## Say hello\n",
    "\n",
    "Read the invoke URL from the Workload and call it. `whoami` will echo request headers and connection info. That's your hello world.\n",
    "\n",
    "> **401 error:** If the call returns `401`, double-check that `DATAROBOT_API_TOKEN` is set and passed in the `Authorization: Bearer` header&mdash;the platform only reports a Workload as `running` once its endpoint is confirmed reachable, so a persistent `401` at that point points to the token rather than a route that hasn't propagated yet."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "eb86ec26",
   "metadata": {},
   "outputs": [],
   "source": [
    "import requests\n",
    "\n",
    "headers = {\"Authorization\": f\"Bearer {os.environ['DATAROBOT_API_TOKEN']}\"}\n",
    "workload = requests.get(\n",
    "    f\"{os.environ['DATAROBOT_ENDPOINT']}/workloads/{workload_id}\", headers=headers\n",
    ").json()\n",
    "endpoint = workload[\"endpoint\"]\n",
    "\n",
    "response = requests.get(endpoint, headers=headers)\n",
    "print(response.status_code)\n",
    "print(response.text)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Clean up\n",
    "\n",
    "`POST /workloads/{id}/stop` stops the underlying proton. Draft Workloads also auto-terminate after 8 hours, so cleanup is optional, but good hygiene."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%bash\n",
    "set -euo pipefail\n",
    "curl -X POST \"${DATAROBOT_ENDPOINT}/workloads/${WORKLOAD_ID}/stop\" \\\n",
    "  -H \"Authorization: Bearer ${DATAROBOT_API_TOKEN}\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Summary\n",
    "\n",
    "In this tutorial:\n",
    "\n",
    "- You created a **draft Workload** from an inline draft artifact (type `service`).\n",
    "- The platform built the container group, ran readiness probes, and assigned an invoke URL.\n",
    "- Because the artifact is `draft`, the Workload is short-lived: 8-hour TTL, one Workload per draft artifact, automatic cleanup."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "name": "python",
   "version": "3.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
