{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Kubernetes Pod Commandline Code Executor"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The `PodCommandLineCodeExecutor` in the `autogen.coding.kubernetes` module is designed to execute code blocks using a pod in Kubernetes.\n",
    "It functions similarly to the `DockerCommandLineCodeExecutor`, but specifically creates container within Kubernetes environments.\n",
    "\n",
    "There are two condition to use PodCommandLineCodeExecutor.\n",
    "- Access to a Kubernetes cluster\n",
    "- installation `autogen` with the extra requirements `'pyautogen[kubernetes]'`\n",
    "\n",
    "For local development and testing, this document uses a Minikube cluster.\n",
    "\n",
    "Minikube is a tool that allows you to run a single-node Kubernetes cluster on you local machine. \n",
    "You can refer to the link below for installation and setup of Minikube.\n",
    "\n",
    "🔗 https://minikube.sigs.k8s.io/docs/start/"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Access kubernetes cluster"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "There are four options PodCommandLineCodeExecutor to access kubernetes API server.\n",
    "- default kubeconfig file path: `~/.kube/config`\n",
    "- Provide a custom kubeconfig file path using the `kube_config_file` argument of `PodCommandLineCodeExecutor`.\n",
    "- Set the kubeconfig file path using the `KUBECONFIG` environment variable.\n",
    "- Provide token from Kubernetes ServiceAccount with sufficient permissions"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Generally, if kubeconfig file is located in `~/.kube/config`, there's no need to provide kubeconfig file path on parameter or environment variables.\n",
    "\n",
    "The tutorial of providing ServiceAccount Token is in the last section"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Example\n",
    "\n",
    "In order to use kubernetes Pod based code executor, you need to install Kubernetes Python SDK.\n",
    "\n",
    "You can do this by running the following command:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pip install 'kubernetes>=27'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Alternatively, you can install it with the extra features for Kubernetes:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pip install 'autogen-agentchat[kubernetes]~=0.2'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To provide kubeconfig file path with environment variable, It can be added with `os.environ[\"KUBECONFIG\"]`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "\n",
    "# Set the KUBECONFIG environment variable\n",
    "# if the kubeconfig file is not in the default location(~/.kube/config).\n",
    "os.environ[\"KUBECONFIG\"] = \"path/to/your/kubeconfig\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "from autogen.coding import CodeBlock\n",
    "from autogen.coding.kubernetes import PodCommandLineCodeExecutor"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "exit_code=0 output='Hello, World!\\n' code_file='/workspace/tmp_code_07da107bb575cc4e02b0e1d6d99cc204.py'\n"
     ]
    }
   ],
   "source": [
    "with PodCommandLineCodeExecutor(\n",
    "    namespace=\"default\",\n",
    "    # kube_config_file=\"kubeconfig/file/path\" # If you have another kubeconfig file, you can add it on kube_config_file argument\n",
    ") as executor:\n",
    "    print(\n",
    "        executor.execute_code_blocks(\n",
    "            # Example of executing a simple Python code block within a Kubernetes pod.\n",
    "            code_blocks=[\n",
    "                CodeBlock(language=\"python\", code=\"print('Hello, World!')\"),\n",
    "            ]\n",
    "        )\n",
    "    )"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Using a context manager(the `with` statement), the pod created by `PodCommandLineCodeExecutor` is automatically deleted after the tasks are completed.\n",
    "\n",
    "Although the pod is automatically deleted when using a context manager, you might sometimes need to delete it manually. You can do this using `stop()` method, as shown below:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "executor = PodCommandLineCodeExecutor(namespace=\"default\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "NAME                                                     READY   STATUS    RESTARTS   AGE\n",
      "autogen-code-exec-afd217ac-f77b-4ede-8c53-1297eca5ec64   1/1     Running   0          10m\n"
     ]
    }
   ],
   "source": [
    "%%bash\n",
    "# This command lists all pods in the default namespace. \n",
    "# The default pod name follows the format autogen-code-exec-{uuid.uuid4()}.\n",
    "kubectl get pod -n default"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "python:3-slim"
     ]
    }
   ],
   "source": [
    "%%bash\n",
    "# This command shows container's image in the pod.\n",
    "# The default container image is python:3-slim\n",
    "kubectl get pod autogen-code-exec-afd217ac-f77b-4ede-8c53-1297eca5ec64 -o jsonpath={.spec.containers[0].image}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "executor.stop()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To use a different container image for code executor pod, specify the desired image tag using `image` argument.\n",
    "\n",
    "`PodCommandLineCodeExecutor` has a default execution policy that allows Python and shell script code blocks. You can enable other languages with `execution_policies` argument."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "exit_code=0 output='Hello, World!\\n' code_file='app/tmp_code_8c34c8586cb47943728afe1297b7a51c.js'\n"
     ]
    }
   ],
   "source": [
    "with PodCommandLineCodeExecutor(\n",
    "    image=\"node:22-alpine\",  # Specifies the runtime environments using a container image\n",
    "    namespace=\"default\",\n",
    "    work_dir=\"./app\",  # Directory within the container where code block files are stored\n",
    "    timeout=10,  # Timeout in seconds for pod creation and code block execution (default is 60 seconds)\n",
    "    execution_policies={\n",
    "        \"javascript\": True\n",
    "    },  # Enable execution of Javascript code blocks by updating execution policies\n",
    ") as executor:\n",
    "    print(\n",
    "        executor.execute_code_blocks(\n",
    "            code_blocks=[\n",
    "                CodeBlock(language=\"javascript\", code=\"console.log('Hello, World!')\"),\n",
    "            ]\n",
    "        )\n",
    "    )"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If you want to apply custom settings for executor pod, such as annotations, environment variables, commands, volumes etc., \n",
    "you can provide a custom pod specification using `kubernetes.client.V1Pod` format.\n",
    "\n",
    "The `container_name` argument should also be provided because `PodCommandLineCodeExecutor` does not automatically recognize the container where code blocks will be executed."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "from kubernetes import client\n",
    "\n",
    "pod = client.V1Pod(\n",
    "    metadata=client.V1ObjectMeta(name=\"abcd\", namespace=\"default\", annotations={\"sidecar.istio.io/inject\": \"false\"}),\n",
    "    spec=client.V1PodSpec(\n",
    "        restart_policy=\"Never\",\n",
    "        containers=[\n",
    "            client.V1Container(\n",
    "                args=[\"-c\", \"while true;do sleep 5; done\"],\n",
    "                command=[\"/bin/sh\"],\n",
    "                name=\"abcd\",  # container name where code blocks will be executed should be provided using `container_name` argument\n",
    "                image=\"python:3.11-slim\",\n",
    "                env=[\n",
    "                    client.V1EnvVar(name=\"TEST\", value=\"TEST\"),\n",
    "                    client.V1EnvVar(\n",
    "                        name=\"POD_NAME\",\n",
    "                        value_from=client.V1EnvVarSource(\n",
    "                            field_ref=client.V1ObjectFieldSelector(field_path=\"metadata.name\")\n",
    "                        ),\n",
    "                    ),\n",
    "                ],\n",
    "            )\n",
    "        ],\n",
    "    ),\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "exit_code=0 output='Hello, World!\\n' code_file='/autogen/tmp_code_07da107bb575cc4e02b0e1d6d99cc204.py'\n",
      "exit_code=0 output='TEST abcd\\n' code_file='/autogen/tmp_code_202399627ea7fb8d8e816f4910b7f87b.sh'\n"
     ]
    }
   ],
   "source": [
    "with PodCommandLineCodeExecutor(\n",
    "    pod_spec=pod,  # custom executor pod spec\n",
    "    container_name=\"abcd\",  # To use custom executor pod spec, container_name where code block will be executed should be specified\n",
    "    work_dir=\"/autogen\",\n",
    "    timeout=60,\n",
    ") as executor:\n",
    "    print(\n",
    "        executor.execute_code_blocks(\n",
    "            code_blocks=[\n",
    "                CodeBlock(language=\"python\", code=\"print('Hello, World!')\"),\n",
    "            ]\n",
    "        )\n",
    "    )\n",
    "    print(\n",
    "        executor.execute_code_blocks(\n",
    "            code_blocks=[\n",
    "                CodeBlock(\n",
    "                    code=\"echo $TEST $POD_NAME\", language=\"bash\"\n",
    "                ),  # echo environment variables specified in pod_spec\n",
    "            ]\n",
    "        )\n",
    "    )"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Integrates with AutoGen Agents"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`PodCommandLineCodeExecutor` can be integrated with Agents."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [],
   "source": [
    "from autogen import config_list_from_json\n",
    "\n",
    "config_list = config_list_from_json(\n",
    "    env_or_file=\"OAI_CONFIG_LIST\",\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[33mcode_executor_agent\u001b[0m (to code_writer):\n",
      "\n",
      "Write Python code to calculate the moves of disk on tower of hanoi with 3 disks\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33mcode_writer\u001b[0m (to code_executor_agent):\n",
      "\n",
      "The problem of the Tower of Hanoi with 3 disks involves moving the disks from one peg to another, following these rules:\n",
      "1. Only one disk can be moved at a time.\n",
      "2. Each move consists of taking the upper disk from one of the stacks and placing it on top of another stack or on an empty peg.\n",
      "3. No disk may be placed on top of a smaller disk.\n",
      "\n",
      "In the solution, I will use a recursive function to calculate the moves and print them out. Here's the Python code to accomplish this:\n",
      "\n",
      "```python\n",
      "def tower_of_hanoi(n, from_rod, to_rod, aux_rod):\n",
      "    if n == 1:\n",
      "        print(f\"Move disk 1 from rod {from_rod} to rod {to_rod}\")\n",
      "        return\n",
      "    tower_of_hanoi(n-1, from_rod, aux_rod, to_rod)\n",
      "    print(f\"Move disk {n} from rod {from_rod} to rod {to_rod}\")\n",
      "    tower_of_hanoi(n-1, aux_rod, to_rod, from_rod)\n",
      "\n",
      "n = 3  # Number of disks\n",
      "tower_of_hanoi(n, 'A', 'C', 'B')  # A, B and C are names of the rods\n",
      "```\n",
      "\n",
      "This script defines a function `tower_of_hanoi` that will print out each move necessary to solve the Tower of Hanoi problem with the specified number of disks `n`. This specific setup will solve for 3 disks moving from rod 'A' to rod 'C' with the help of rod 'B'.\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[31m\n",
      ">>>>>>>> EXECUTING CODE BLOCK (inferred language is python)...\u001b[0m\n",
      "\u001b[33mcode_executor_agent\u001b[0m (to code_writer):\n",
      "\n",
      "exitcode: 0 (execution succeeded)\n",
      "Code output: Move disk 1 from rod A to rod C\n",
      "Move disk 2 from rod A to rod B\n",
      "Move disk 1 from rod C to rod B\n",
      "Move disk 3 from rod A to rod C\n",
      "Move disk 1 from rod B to rod A\n",
      "Move disk 2 from rod B to rod C\n",
      "Move disk 1 from rod A to rod C\n",
      "\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33mcode_writer\u001b[0m (to code_executor_agent):\n",
      "\n",
      "The execution of the provided code successfully calculated and printed the moves for solving the Tower of Hanoi with 3 disks. Here are the steps it performed:\n",
      "\n",
      "1. Move disk 1 from rod A to rod C.\n",
      "2. Move disk 2 from rod A to rod B.\n",
      "3. Move disk 1 from rod C to rod B.\n",
      "4. Move disk 3 from rod A to rod C.\n",
      "5. Move disk 1 from rod B to rod A.\n",
      "6. Move disk 2 from rod B to rod C.\n",
      "7. Move disk 1 from rod A to rod C.\n",
      "\n",
      "This sequence effectively transfers all disks from rod A to rod C using rod B as an auxiliary, following the rules of the Tower of Hanoi puzzle. If you have any more tasks or need further explanation, feel free to ask!\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33mcode_executor_agent\u001b[0m (to code_writer):\n",
      "\n",
      "\n",
      "\n",
      "--------------------------------------------------------------------------------\n"
     ]
    }
   ],
   "source": [
    "from autogen import ConversableAgent\n",
    "\n",
    "# The code writer agent's system message is to instruct the LLM on how to\n",
    "# use the code executor with python or shell script code\n",
    "code_writer_system_message = \"\"\"\n",
    "You have been given coding capability to solve tasks using Python code.\n",
    "In the following cases, suggest python code (in a python coding block) or shell script (in a sh coding block) for the user to execute.\n",
    "    1. When you need to collect info, use the code to output the info you need, for example, browse or search the web, download/read a file, print the content of a webpage or a file, get the current date/time, check the operating system. After sufficient info is printed and the task is ready to be solved based on your language skill, you can solve the task by yourself.\n",
    "    2. When you need to perform some task with code, use the code to perform the task and output the result. Finish the task smartly.\n",
    "Solve the task step by step if you need to. If a plan is not provided, explain your plan first. Be clear which step uses code, and which step uses your language skill.\n",
    "When using code, you must indicate the script type in the code block. The user cannot provide any other feedback or perform any other action beyond executing the code you suggest. The user can't modify your code. So do not suggest incomplete code which requires users to modify. Don't use a code block if it's not intended to be executed by the user.\n",
    "If you want the user to save the code in a file before executing it, put # filename: <filename> inside the code block as the first line. Don't include multiple code blocks in one response. Do not ask users to copy and paste the result. Instead, use 'print' function for the output when relevant. Check the execution result returned by the user.\n",
    "\"\"\"\n",
    "with PodCommandLineCodeExecutor(namespace=\"default\") as executor:\n",
    "\n",
    "    code_executor_agent = ConversableAgent(\n",
    "        name=\"code_executor_agent\",\n",
    "        llm_config=False,\n",
    "        code_execution_config={\n",
    "            \"executor\": executor,\n",
    "        },\n",
    "        human_input_mode=\"NEVER\",\n",
    "    )\n",
    "\n",
    "    code_writer_agent = ConversableAgent(\n",
    "        \"code_writer\",\n",
    "        system_message=code_writer_system_message,\n",
    "        llm_config={\"config_list\": config_list},\n",
    "        code_execution_config=False,  # Turn off code execution for this agent.\n",
    "        max_consecutive_auto_reply=2,\n",
    "        human_input_mode=\"NEVER\",\n",
    "    )\n",
    "\n",
    "    chat_result = code_executor_agent.initiate_chat(\n",
    "        code_writer_agent, message=\"Write Python code to calculate the moves of disk on tower of hanoi with 10 disks\"\n",
    "    )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "93802984-3207-430b-a205-82f0a77df2b2",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "ChatResult(chat_id=None,\n",
      "           chat_history=[{'content': 'Write Python code to calculate the moves '\n",
      "                                     'of disk on tower of hanoi with 3 disks',\n",
      "                          'name': 'code_executor_agent',\n",
      "                          'role': 'assistant'},\n",
      "                         {'content': 'The problem of the Tower of Hanoi with 3 '\n",
      "                                     'disks involves moving the disks from one '\n",
      "                                     'peg to another, following these rules:\\n'\n",
      "                                     '1. Only one disk can be moved at a '\n",
      "                                     'time.\\n'\n",
      "                                     '2. Each move consists of taking the '\n",
      "                                     'upper disk from one of the stacks and '\n",
      "                                     'placing it on top of another stack or on '\n",
      "                                     'an empty peg.\\n'\n",
      "                                     '3. No disk may be placed on top of a '\n",
      "                                     'smaller disk.\\n'\n",
      "                                     '\\n'\n",
      "                                     'In the solution, I will use a recursive '\n",
      "                                     'function to calculate the moves and '\n",
      "                                     \"print them out. Here's the Python code \"\n",
      "                                     'to accomplish this:\\n'\n",
      "                                     '\\n'\n",
      "                                     '```python\\n'\n",
      "                                     'def tower_of_hanoi(n, from_rod, to_rod, '\n",
      "                                     'aux_rod):\\n'\n",
      "                                     '    if n == 1:\\n'\n",
      "                                     '        print(f\"Move disk 1 from rod '\n",
      "                                     '{from_rod} to rod {to_rod}\")\\n'\n",
      "                                     '        return\\n'\n",
      "                                     '    tower_of_hanoi(n-1, from_rod, '\n",
      "                                     'aux_rod, to_rod)\\n'\n",
      "                                     '    print(f\"Move disk {n} from rod '\n",
      "                                     '{from_rod} to rod {to_rod}\")\\n'\n",
      "                                     '    tower_of_hanoi(n-1, aux_rod, to_rod, '\n",
      "                                     'from_rod)\\n'\n",
      "                                     '\\n'\n",
      "                                     'n = 3  # Number of disks\\n'\n",
      "                                     \"tower_of_hanoi(n, 'A', 'C', 'B')  # A, B \"\n",
      "                                     'and C are names of the rods\\n'\n",
      "                                     '```\\n'\n",
      "                                     '\\n'\n",
      "                                     'This script defines a function '\n",
      "                                     '`tower_of_hanoi` that will print out '\n",
      "                                     'each move necessary to solve the Tower '\n",
      "                                     'of Hanoi problem with the specified '\n",
      "                                     'number of disks `n`. This specific setup '\n",
      "                                     'will solve for 3 disks moving from rod '\n",
      "                                     \"'A' to rod 'C' with the help of rod 'B'.\",\n",
      "                          'name': 'code_writer',\n",
      "                          'role': 'user'},\n",
      "                         {'content': 'exitcode: 0 (execution succeeded)\\n'\n",
      "                                     'Code output: Move disk 1 from rod A to '\n",
      "                                     'rod C\\n'\n",
      "                                     'Move disk 2 from rod A to rod B\\n'\n",
      "                                     'Move disk 1 from rod C to rod B\\n'\n",
      "                                     'Move disk 3 from rod A to rod C\\n'\n",
      "                                     'Move disk 1 from rod B to rod A\\n'\n",
      "                                     'Move disk 2 from rod B to rod C\\n'\n",
      "                                     'Move disk 1 from rod A to rod C\\n',\n",
      "                          'name': 'code_executor_agent',\n",
      "                          'role': 'assistant'},\n",
      "                         {'content': 'The execution of the provided code '\n",
      "                                     'successfully calculated and printed the '\n",
      "                                     'moves for solving the Tower of Hanoi '\n",
      "                                     'with 3 disks. Here are the steps it '\n",
      "                                     'performed:\\n'\n",
      "                                     '\\n'\n",
      "                                     '1. Move disk 1 from rod A to rod C.\\n'\n",
      "                                     '2. Move disk 2 from rod A to rod B.\\n'\n",
      "                                     '3. Move disk 1 from rod C to rod B.\\n'\n",
      "                                     '4. Move disk 3 from rod A to rod C.\\n'\n",
      "                                     '5. Move disk 1 from rod B to rod A.\\n'\n",
      "                                     '6. Move disk 2 from rod B to rod C.\\n'\n",
      "                                     '7. Move disk 1 from rod A to rod C.\\n'\n",
      "                                     '\\n'\n",
      "                                     'This sequence effectively transfers all '\n",
      "                                     'disks from rod A to rod C using rod B as '\n",
      "                                     'an auxiliary, following the rules of the '\n",
      "                                     'Tower of Hanoi puzzle. If you have any '\n",
      "                                     'more tasks or need further explanation, '\n",
      "                                     'feel free to ask!',\n",
      "                          'name': 'code_writer',\n",
      "                          'role': 'user'},\n",
      "                         {'content': '',\n",
      "                          'name': 'code_executor_agent',\n",
      "                          'role': 'assistant'}],\n",
      "           summary='',\n",
      "           cost={'usage_excluding_cached_inference': {'total_cost': 0},\n",
      "                 'usage_including_cached_inference': {'gpt-4-turbo-2024-04-09': {'completion_tokens': 499,\n",
      "                                                                                 'cost': 0.0269,\n",
      "                                                                                 'prompt_tokens': 1193,\n",
      "                                                                                 'total_tokens': 1692},\n",
      "                                                      'total_cost': 0.0269}},\n",
      "           human_input=[])\n"
     ]
    }
   ],
   "source": [
    "import pprint\n",
    "\n",
    "pprint.pprint(chat_result)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Use ServiceAccount token"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If a `PodCommandLineCodeExecutor` instance runs inside of Kubernetes Pod, it can use a token generated from a ServiceAccount to access Kubernetes API server.\n",
    "\n",
    "The `PodCommandLineCodeExecutor` requires the following permissions:\n",
    "the verbs `create`, `get`, `delete` for `pods` resource, and the verb `get` for resources `pods/status`, `pods/exec`.\n",
    "\n",
    "You can create a ServiceAccount, ClusterRole and RoleBinding with `kubectl` as shown below:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "serviceaccount/autogen-executor-sa created\n"
     ]
    }
   ],
   "source": [
    "%%bash\n",
    "# Create ServiceAccount on default namespace\n",
    "kubectl create sa autogen-executor-sa"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "clusterrole.rbac.authorization.k8s.io/autogen-executor-role created\n"
     ]
    }
   ],
   "source": [
    "%%bash\n",
    "# Create ClusterRole that has sufficient permissions\n",
    "kubectl create clusterrole autogen-executor-role \\\n",
    "    --verb=get,create,delete --resource=pods,pods/status,pods/exec"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "rolebinding.rbac.authorization.k8s.io/autogen-executor-rolebinding created\n"
     ]
    }
   ],
   "source": [
    "%%bash\n",
    "# Create RoleBinding that binds ClusterRole and ServiceAccount\n",
    "kubectl create rolebinding autogen-executor-rolebinding \\\n",
    "    --clusterrole autogen-executor-role --serviceaccount default:autogen-executor-sa"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A pod with a previously created ServiceAccount can be launched using the following command."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "pod/autogen-executor created\n"
     ]
    }
   ],
   "source": [
    "%%bash\n",
    "# create pod with serviceaccount\n",
    "kubectl run autogen-executor --image python:3 \\\n",
    "    --overrides='{\"spec\":{\"serviceAccount\": \"autogen-executor-sa\"}}' \\\n",
    "        -- bash -c 'pip install pyautogen[kubernetes] && sleep inifinity'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can execute `PodCommandLineCodeExecutor` inside the Python interpreter process from `autogen-executor` Pod.\n",
    "\n",
    "It creates new pod for code execution using token generated from `autogen-executor-sa` ServiceAccount."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%bash\n",
    "kubectl exec autogen-executor -it -- python"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "kube_config_path not provided and default location (~/.kube/config) does not exist. Using inCluster Config. This might not work.\n",
      "exit_code=0 output='Hello, World!\\n' code_file='/workspace/tmp_code_07da107bb575cc4e02b0e1d6d99cc204.py'"
     ]
    }
   ],
   "source": [
    "from autogen.coding import CodeBlock\n",
    "from autogen.coding.kubernetes import PodCommandLineCodeExecutor\n",
    "\n",
    "# PodCommandLineCodeExecutor uses token generated from ServiceAccount by kubernetes incluster config\n",
    "with PodCommandLineCodeExecutor() as executor:\n",
    "    print(\n",
    "        executor.execute_code_blocks(\n",
    "            code_blocks=[\n",
    "                CodeBlock(language=\"python\", code=\"print('Hello, World!')\"),\n",
    "            ]\n",
    "        )\n",
    "    )"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "autogen",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
