kubernetes-robin-executor 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
File without changes
@@ -0,0 +1,230 @@
1
+ # `KubernetesCommandLineCodeExecutor`
2
+
3
+ Executor that runs code (Python / shell) **inside a Kubernetes pod**: each block is written as a file on the pod’s workspace volume and executed via `exec` (Kubernetes API + stream).
4
+
5
+ **PyPI distribution name:** `kubernetes-robin-executor` — install with:
6
+
7
+ ```bash
8
+ pip install kubernetes-robin-executor
9
+ ```
10
+
11
+ **Import path** (unchanged): `autogen_kubernetes.code_executors.kubernetes_commandline_code_executor`. The PyPI name differs from the upstream `autogen-kubernetes` package on purpose. Do not install both in the same environment if they expose the same top-level package layout; this distribution keeps the `autogen_kubernetes` module name for compatibility with existing code.
12
+
13
+ This file is the **project `readme`** in `pyproject.toml`, so it is what users see on the [PyPI project page](https://pypi.org) for `kubernetes-robin-executor` after you publish.
14
+
15
+ ---
16
+
17
+ ## Cluster connection
18
+
19
+ | Mode | Behavior |
20
+ |------|----------|
21
+ | **`remote_control_plane` set** (API URL, e.g. `https://IP:6443`) | Uses `KUBE_TOKEN` from the environment (Bearer). Client uses `verify_ssl=False`. |
22
+ | **`remote_control_plane=None`** | Local `kubeconfig` or in-cluster config (`load_kube_config` / `load_incluster_config`). |
23
+
24
+ ---
25
+
26
+ ## Constructor (`__init__`)
27
+
28
+ Main parameters:
29
+
30
+ | Parameter | Description |
31
+ |-----------|-------------|
32
+ | `image` | Container image (default `python:3-slim`). |
33
+ | `pod_name` | Fixed pod name; if `None`, generates `robin-code-exec-<uuid>`. |
34
+ | `namespace` | Namespace where the pod is created / listed. |
35
+ | `timeout` | Seconds for exec-based runs (≥ 1). |
36
+ | `work_dir` | Path **inside the pod** mounted as the workspace. |
37
+ | `execution_policies` | Optional: override which languages are **executed** vs only **saved**. |
38
+ | `remote_control_plane` | API server URL for bearer-token mode. |
39
+ | `shared_pvc_name` | If set, the pod uses a shared PVC instead of `emptyDir`. |
40
+ | `node` | Optional: `nodeSelector` `kubernetes.io/hostname`. |
41
+ | `shared_resources` | If `True` and a **Running** pod already exists with the **same** `image`, reuses its name instead of creating a new pod. |
42
+ | `env_vars` | List of `{"key": "...", "value": "..."}` appended to `~/.bashrc` in the pod. |
43
+
44
+ On construction, pod cleanup is registered with `atexit` and `SIGINT` is handled with `cleanup()`.
45
+
46
+ ---
47
+
48
+ ## Upload code from your machine and call functions in the pod
49
+
50
+ Besides `execute_code_blocks`, you can **copy Python files into the pod’s `work_dir`** and **invoke callables by name** without putting everything in a single markdown block.
51
+
52
+ ### Recommended flow
53
+
54
+ 1. **`install_pod_dispatcher(default_module="robin_user", runner_filename="executor.py")`** — Uploads an `executor.py` that reads JSON with `function`, `arguments`, and optionally `module`, imports the module, and calls `function(**arguments)`.
55
+ 2. **`upload_file_content(relative_path, content)`** or **`upload_from_disk(local_path, remote_prefix="")`** — Copies your `.py` files or project tree into the pod under `work_dir`. `upload_from_disk` skips `__pycache__` and hidden names (`.*`); text files only (UTF-8).
56
+ 3. **`execute_tool_function(arguments, func_name, *, module=None, runner_script="executor.py")`** — Uploads a temporary `.json` and runs `python <work_dir>/<runner_script> <json>`.
57
+
58
+ The interpreter adds the script’s directory to `sys.path`; with `executor.py` in `work_dir`, modules in the same directory (e.g. `robin_user.py`) or packages under `work_dir` can be imported using the right `module` (e.g. `my_package.submodule`).
59
+
60
+ ### Minimal example
61
+
62
+ ```python
63
+ with KubernetesCommandLineCodeExecutor(...) as executor:
64
+ executor.install_pod_dispatcher(default_module="robin_user")
65
+ executor.upload_from_disk("/local/path/my_folder") # contains robin_user.py or your layout
66
+ r = executor.execute_tool_function(
67
+ {"name": "Ada"},
68
+ "greet",
69
+ module="robin_user",
70
+ )
71
+ assert r.exit_code == 0
72
+ ```
73
+
74
+ If you omit `module` in `execute_tool_function`, the dispatcher uses the `default_module` passed to `install_pod_dispatcher`.
75
+
76
+ ### Integration test in this repo
77
+
78
+ `test_upload_from_disk_and_invoke_long_function` uploads `tests/fixtures/robin_upload_invoke/robin_user.py` and calls `greet` and `run_heavy_pipeline` on the pod (marker `robin_remote`; see `tests/README.md`).
79
+
80
+ Run it from `autogen-kubernetes/python`:
81
+
82
+ ```bash
83
+ uv run pytest packages/autogen-kubernetes/tests/test_kubernetes_commandline_executor.py::test_upload_from_disk_and_invoke_long_function -m robin_remote -v -s -n0
84
+ ```
85
+
86
+ ---
87
+
88
+ ## Public properties
89
+
90
+ | Member | Type / return | Description |
91
+ |--------|----------------|-------------|
92
+ | `timeout` | `int` | Configured timeout. |
93
+ | `work_dir` | `Path` | Working directory in the pod. |
94
+ | `code_extractor` | `MarkdownCodeExtractor` | Code-block extractor for agent integration. |
95
+ | `execution_policies` | `dict` | Per language: `True` runs, `False` only writes the file. |
96
+ | `pod_name` | `str` | Pod name in use (created or reused). |
97
+ | `namespace` | `str` | Current namespace. |
98
+ | `image` | `str` | Container image. |
99
+
100
+ ---
101
+
102
+ ## Public methods
103
+
104
+ | Method | Description |
105
+ |--------|-------------|
106
+ | `execute_code_blocks(code_blocks: list[CodeBlock]) -> CommandLineCodeResult` | Uploads and runs (or only saves) each block in order. Returns `exit_code`, `output` (combined stdout/stderr), and `code_file`. |
107
+ | `upload_file_content(relative_path, content) -> str` | Writes text in the pod under `work_dir` / `relative_path`; returns the POSIX path in the pod. |
108
+ | `upload_from_disk(local_path, *, remote_prefix="", encoding="utf-8") -> list[str]` | Uploads a local file or full directory tree; returns paths written in the pod. |
109
+ | `install_pod_dispatcher(*, default_module="robin_user", runner_filename="executor.py") -> str` | Uploads the `executor.py` that dispatches JSON → function calls in the pod. |
110
+ | `execute_tool_function(arguments, func_name, *, module=None, runner_script="executor.py") -> CommandLineCodeResult` | Uploads JSON and runs the runner (default `executor.py` in `work_dir`). Use `install_pod_dispatcher` or your own script in the image. `module` is the dotted import if you do not want the dispatcher’s `default_module`. |
111
+ | `cleanup()` | Deletes the pod in the namespace (404-safe). |
112
+ | `stop()` | Runs the registered cleanup (`delete` pod). |
113
+ | `restart()` | `stop()` then calls `__init__` again with a subset of arguments (**note**: remote mode may omit `remote_control_plane`; prefer recreating the executor manually if this fails). |
114
+ | `add_env_vars_to_bashrc(env_vars)` | Appends exports to `~/.bashrc` via exec. |
115
+ | `is_pod_running_with_image()` | Lists pods in the namespace; if one is **Running** with `self.image`, returns its **name** (`str`); otherwise `None`. |
116
+ | `get_pod_resource_usage()` | Tries to read `metrics.k8s.io` (often assumes local `kubeconfig`; may not work with remote token only). |
117
+ | `create_resources()` | Creates the pod and waits for `Running` (usually already called from `__init__`). |
118
+ | `handle_sigint(signum, frame)` | Signal handler: cleans up and exits the process. |
119
+
120
+ **Context manager:** `__enter__` / `__exit__` → leaving `with` calls `stop()` (deletes the pod if cleanup is active).
121
+
122
+ **Internals (reference):** `_upload_file_to_pod`, `_exec_command_with_exit_code`, `_wait_for_pod_ready` — upload via stdin to exec, command wrapped in `sh -c` with exit-code capture.
123
+
124
+ ---
125
+
126
+ ## Examples
127
+
128
+ ### 1. Remote cluster with token (`.env`: `KUBE_TOKEN`; your app often also sets `REMOTE_CONTROL_PLANE`)
129
+
130
+ ```python
131
+ import os
132
+ from autogen_kubernetes.code_executors.base import CodeBlock
133
+ from autogen_kubernetes.code_executors.kubernetes_commandline_code_executor import (
134
+ KubernetesCommandLineCodeExecutor,
135
+ )
136
+
137
+ os.environ.setdefault("KUBE_TOKEN", "...") # or load_dotenv()
138
+
139
+ with KubernetesCommandLineCodeExecutor(
140
+ image="williamgomez712/robin_executor_python:latest",
141
+ namespace="my-namespace",
142
+ work_dir="/tmp/robin_executor_test",
143
+ timeout=120,
144
+ remote_control_plane="https://API_SERVER:6443",
145
+ shared_resources=False,
146
+ ) as executor:
147
+ result = executor.execute_code_blocks(
148
+ [CodeBlock(language="python", code="print('hello')")]
149
+ )
150
+ print(result.exit_code, result.output)
151
+ ```
152
+
153
+ ### 2. Save file on the pod only (do not execute)
154
+
155
+ ```python
156
+ executor.execution_policies["python"] = False
157
+ result = executor.execute_code_blocks(
158
+ [CodeBlock(language="python", code="print('does not run')")]
159
+ )
160
+ # result.output will include "Code saved to ..."
161
+ ```
162
+
163
+ ### 3. Shell in the pod
164
+
165
+ ```python
166
+ result = executor.execute_code_blocks(
167
+ [CodeBlock(language="sh", code="echo ok && uname -a")]
168
+ )
169
+ ```
170
+
171
+ ### 4. Tooling via uploaded dispatcher (`install_pod_dispatcher`) or `executor.py` baked into the image
172
+
173
+ ```python
174
+ executor.install_pod_dispatcher(default_module="robin_user")
175
+ executor.upload_file_content("robin_user.py", open("robin_user.py").read())
176
+ result = executor.execute_tool_function(
177
+ {"query": "test"},
178
+ func_name="my_function",
179
+ module="robin_user",
180
+ )
181
+ ```
182
+
183
+ If the image already provides `executor.py` under `work_dir`, you can call `execute_tool_function` alone without `install_pod_dispatcher`.
184
+
185
+ ### 5. Local cluster / kubeconfig (no `remote_control_plane`)
186
+
187
+ ```python
188
+ with KubernetesCommandLineCodeExecutor(
189
+ namespace="default",
190
+ work_dir="/tmp/work",
191
+ ) as executor:
192
+ ...
193
+ ```
194
+
195
+ (Requires a valid `~/.kube/config` or in-cluster execution.)
196
+
197
+ ---
198
+
199
+ ## `CommandLineCodeResult`
200
+
201
+ | Field | Meaning |
202
+ |-------|---------|
203
+ | `exit_code` | Exit code of the last relevant command in the sequence. |
204
+ | `output` | Accumulated text (stdout/stderr from exec). |
205
+ | `code_file` | Path of the first generated code file in the pod (if any). |
206
+
207
+ ---
208
+
209
+ ## Practical notes
210
+
211
+ - **`shared_resources=True`**: reuses a pod with the same `image`; the existing pod’s `work_dir` must match what your code expects, or you may see “file not found” errors.
212
+ - **Filename hints in code**: the first line can set a path with comments like `# filename: foo.py` (and HTML/JS patterns); otherwise a `tmp_code_<md5>.<lang>` under `work_dir` is used.
213
+ - **RBAC**: the token or kubeconfig user needs `pods` + `pods/exec` (and create/delete depending on your flow).
214
+ - After **`stop()`** / exiting **`with`**, the pod is usually **deleted**; do not expect it to remain for debugging unless you skip cleanup or use another workflow.
215
+
216
+ ---
217
+
218
+ ## Publishing to PyPI
219
+
220
+ - **`[project] name`** is **`kubernetes-robin-executor`**. **`readme`** points at **this file**, so PyPI’s long description matches this document.
221
+
222
+ - **Manifest:** `autogen-kubernetes/python/packages/autogen-kubernetes/pyproject.toml` (relative to the `autogen-kubernetes` clone).
223
+
224
+ - **Consumers** (same as local install from PyPI):
225
+
226
+ ```bash
227
+ pip install kubernetes-robin-executor
228
+ ```
229
+
230
+ - **Step-by-step** build/upload (tokens, TestPyPI, `twine`) is in **`tests/PYPI-publish.local.md`** next to the test suite. That file may be **gitignored** in your outer repo; **`tests/README.md`** mentions it.
@@ -0,0 +1,22 @@
1
+ from ._jupyter_server import (
2
+ PodJupyterConnectionInfo,
3
+ PodJupyterServer,
4
+ PodJupyterServerConfig,
5
+ )
6
+ from ._kubernetes_code_executor import (
7
+ PodCommandLineCodeExecutor,
8
+ PodCommandLineCodeExecutorConfig,
9
+ )
10
+ from ._kubernetes_jupyter import PodJupyterCodeExecutor, PodJupyterCodeExecutorConfig
11
+
12
+ __all__ = [
13
+ "PodCommandLineCodeExecutor",
14
+ "PodCommandLineCodeExecutorConfig",
15
+ "PodJupyterCodeExecutor",
16
+ "PodJupyterCodeExecutorConfig",
17
+ "PodJupyterServer",
18
+ "PodJupyterServerConfig",
19
+ "PodJupyterConnectionInfo",
20
+ "base",
21
+ "PodJupyterConnectionInfo",
22
+ ]