[SIMPL-30451] Distributed execution reference service and container-cluster configuration guide #1
@@ -1,151 +0,0 @@
|
|||||||
name: Build and Push Docker Images
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
env:
|
|
||||||
BASE_DOMAIN: dataprovider01.sandbox-cat-dat.simpl-europe.eu
|
|
||||||
OWNER: j.r
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build-and-push:
|
|
||||||
runs-on: orchestration-platform
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
shell: sh
|
|
||||||
env:
|
|
||||||
REGISTRY: gitea.${{ env.BASE_DOMAIN }}
|
|
||||||
IMAGE_REPO: gitea.${{ env.BASE_DOMAIN }}/${{ env.OWNER }}/distributed-execution
|
|
||||||
PAYLOAD_IMAGE_REPO: gitea.${{ env.BASE_DOMAIN }}/${{ env.OWNER }}/distributed-execution-payload
|
|
||||||
REPO_DIR: repo
|
|
||||||
REPO_CLONE_URL: https://gitea.${{ env.BASE_DOMAIN }}/${{ env.OWNER }}/distributed-execution.git
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository (shell)
|
|
||||||
run: |
|
|
||||||
CLONE_USER="${{ secrets.REGISTRY_USERNAME }}"
|
|
||||||
CLONE_PASS="${{ secrets.REGISTRY_PASSWORD }}"
|
|
||||||
REF_NAME="${GITHUB_REF_NAME}"
|
|
||||||
if [ -z "${REF_NAME}" ]; then
|
|
||||||
REF_NAME="${GITHUB_REF#refs/heads/}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "${CLONE_USER}" ] || [ -z "${CLONE_PASS}" ]; then
|
|
||||||
echo "Missing REGISTRY_USERNAME or REGISTRY_PASSWORD secret"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
rm -rf "${REPO_DIR}"
|
|
||||||
AUTH_HEADER="$(printf '%s:%s' "${CLONE_USER}" "${CLONE_PASS}" | base64 | tr -d '\n')"
|
|
||||||
git clone --depth 1 --branch "${REF_NAME}" \
|
|
||||||
-c "http.extraHeader=Authorization: Basic ${AUTH_HEADER}" \
|
|
||||||
"${REPO_CLONE_URL}" \
|
|
||||||
"${REPO_DIR}"
|
|
||||||
|
|
||||||
if [ ! -f "${REPO_DIR}/Dockerfile" ]; then
|
|
||||||
echo "Code location Dockerfile not found after clone"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! -f "${REPO_DIR}/payload/Dockerfile" ]; then
|
|
||||||
echo "Payload Dockerfile not found after clone"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Validate registry secrets
|
|
||||||
run: |
|
|
||||||
if [ -z "${{ secrets.REGISTRY_USERNAME }}" ] || [ -z "${{ secrets.REGISTRY_PASSWORD }}" ]; then
|
|
||||||
echo "Missing REGISTRY_USERNAME or REGISTRY_PASSWORD secret"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Login to registry
|
|
||||||
run: |
|
|
||||||
echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login "${REGISTRY}" \
|
|
||||||
-u "${{ secrets.REGISTRY_USERNAME }}" --password-stdin
|
|
||||||
|
|
||||||
# Both images take the same SHA tag: that is what keeps the code location and
|
|
||||||
# the payload it dispatches on the same version.
|
|
||||||
- name: Build code location image
|
|
||||||
run: |
|
|
||||||
COMMIT_SHA="${GITHUB_SHA:-$GITEA_SHA}"
|
|
||||||
SHORT_SHA="$(echo "${COMMIT_SHA}" | cut -c1-12)"
|
|
||||||
cd "${REPO_DIR}"
|
|
||||||
docker build \
|
|
||||||
-t "${IMAGE_REPO}:latest" \
|
|
||||||
-t "${IMAGE_REPO}:${SHORT_SHA}" \
|
|
||||||
.
|
|
||||||
|
|
||||||
- name: Build payload image
|
|
||||||
run: |
|
|
||||||
COMMIT_SHA="${GITHUB_SHA:-$GITEA_SHA}"
|
|
||||||
SHORT_SHA="$(echo "${COMMIT_SHA}" | cut -c1-12)"
|
|
||||||
cd "${REPO_DIR}"
|
|
||||||
docker build \
|
|
||||||
-f payload/Dockerfile \
|
|
||||||
-t "${PAYLOAD_IMAGE_REPO}:latest" \
|
|
||||||
-t "${PAYLOAD_IMAGE_REPO}:${SHORT_SHA}" \
|
|
||||||
payload/
|
|
||||||
|
|
||||||
- name: Validate code location image
|
|
||||||
run: |
|
|
||||||
COMMIT_SHA="${GITHUB_SHA:-$GITEA_SHA}"
|
|
||||||
SHORT_SHA="$(echo "${COMMIT_SHA}" | cut -c1-12)"
|
|
||||||
docker run --rm "${IMAGE_REPO}:${SHORT_SHA}" \
|
|
||||||
dagster definitions validate -f src/distributed_execution/repository.py
|
|
||||||
docker run --rm "${IMAGE_REPO}:${SHORT_SHA}" \
|
|
||||||
test -f /app/payload/work.py
|
|
||||||
|
|
||||||
# Readiness checklist L11: the payload image must not carry the orchestration
|
|
||||||
# runtime, otherwise the isolation argument for the loosely coupled target is void.
|
|
||||||
- name: Validate payload image isolation
|
|
||||||
run: |
|
|
||||||
COMMIT_SHA="${GITHUB_SHA:-$GITEA_SHA}"
|
|
||||||
SHORT_SHA="$(echo "${COMMIT_SHA}" | cut -c1-12)"
|
|
||||||
docker run --rm "${PAYLOAD_IMAGE_REPO}:${SHORT_SHA}" python -c "
|
|
||||||
import importlib.util
|
|
||||||
assert importlib.util.find_spec('dagster_pipes') is not None, 'dagster_pipes missing from payload image'
|
|
||||||
assert importlib.util.find_spec('dagster') is None, 'payload image must not contain the dagster package'
|
|
||||||
print('payload isolation OK')
|
|
||||||
"
|
|
||||||
|
|
||||||
- name: Push code location image tags
|
|
||||||
run: |
|
|
||||||
COMMIT_SHA="${GITHUB_SHA:-$GITEA_SHA}"
|
|
||||||
SHORT_SHA="$(echo "${COMMIT_SHA}" | cut -c1-12)"
|
|
||||||
docker push "${IMAGE_REPO}:latest"
|
|
||||||
docker push "${IMAGE_REPO}:${SHORT_SHA}"
|
|
||||||
|
|
||||||
- name: Push payload image tags
|
|
||||||
run: |
|
|
||||||
COMMIT_SHA="${GITHUB_SHA:-$GITEA_SHA}"
|
|
||||||
SHORT_SHA="$(echo "${COMMIT_SHA}" | cut -c1-12)"
|
|
||||||
docker push "${PAYLOAD_IMAGE_REPO}:latest"
|
|
||||||
docker push "${PAYLOAD_IMAGE_REPO}:${SHORT_SHA}"
|
|
||||||
|
|
||||||
- name: Report image references
|
|
||||||
run: |
|
|
||||||
COMMIT_SHA="${GITHUB_SHA:-$GITEA_SHA}"
|
|
||||||
SHORT_SHA="$(echo "${COMMIT_SHA}" | cut -c1-12)"
|
|
||||||
echo "Code location image: ${IMAGE_REPO}:${SHORT_SHA}"
|
|
||||||
echo "Payload image: ${PAYLOAD_IMAGE_REPO}:${SHORT_SHA}"
|
|
||||||
echo ""
|
|
||||||
echo "Set PIPES_PAYLOAD_IMAGE on both the code location and the run pods:"
|
|
||||||
echo " PIPES_PAYLOAD_IMAGE=${PAYLOAD_IMAGE_REPO}:${SHORT_SHA}"
|
|
||||||
echo "See yaml/loosely-coupled/values-pipes-payload.yaml."
|
|
||||||
|
|
||||||
# The automated update of the deployment requires a technical user with
|
|
||||||
# their kube config in the secrets. See the template repository's user manual.
|
|
||||||
# - name: Update Dagster user deployment image
|
|
||||||
# run: |
|
|
||||||
# COMMIT_SHA="${GITHUB_SHA:-$GITEA_SHA}"
|
|
||||||
# SHORT_SHA="$(echo "${COMMIT_SHA}" | cut -c1-12)"
|
|
||||||
# kubectl patch deployment "${DEPLOYMENT_NAME}" \
|
|
||||||
# -n "${K8S_NAMESPACE}" \
|
|
||||||
# --type='strategic' \
|
|
||||||
# -p="{\"spec\":{\"template\":{\"spec\":{\"containers\":[{\"name\":\"dagster-user-deployments\",\"image\":\"${IMAGE_REPO}:${SHORT_SHA}\",\"env\":[{\"name\":\"DAGSTER_CURRENT_IMAGE\",\"value\":\"${IMAGE_REPO}:${SHORT_SHA}\"},{\"name\":\"PIPES_PAYLOAD_IMAGE\",\"value\":\"${PAYLOAD_IMAGE_REPO}:${SHORT_SHA}\"}]}]}}}}"
|
|
||||||
# kubectl rollout status deployment/"${DEPLOYMENT_NAME}" \
|
|
||||||
# -n "${K8S_NAMESPACE}" \
|
|
||||||
# --timeout=5m
|
|
||||||
@@ -1,3 +1 @@
|
|||||||
# All subgroup members as Code Owners for all files
|
* @simpl/simpl-users/sc1/codeowners/data-supporting-data-services-distributed-execution-distributed-execution
|
||||||
|
|
||||||
* @simpl/simpl-open/data/supporting-data-services
|
|
||||||
28
CHANGELOG.md
28
CHANGELOG.md
@@ -4,15 +4,33 @@
|
|||||||
|
|
||||||
- Repository skeleton for the `distributed-execution` supporting data service.
|
- Repository skeleton for the `distributed-execution` supporting data service.
|
||||||
- User guide covering execution-target selection, decision support and readiness checks.
|
- User guide covering execution-target selection, decision support and readiness checks.
|
||||||
|
- Cluster-configuration input reference: mandatory versus optional inputs per setup,
|
||||||
|
a reusable minimum input set and worked examples in both setups' own formats.
|
||||||
|
- Requirement traceability mapping the guide's sections onto SIMPL-30451 and SIMPL-30787.
|
||||||
- Runnable tightly coupled reference implementations (`in_process`, `multiprocess`, `k8s_job_executor`).
|
- Runnable tightly coupled reference implementations (`in_process`, `multiprocess`, `k8s_job_executor`).
|
||||||
- Runnable loosely coupled reference implementations via dagster-pipes
|
- Runnable loosely coupled reference implementations via dagster-pipes
|
||||||
(`PipesSubprocessClient`, `PipesK8sClient`) with a standalone external payload image.
|
(`PipesSubprocessClient`, `PipesK8sClient`) with a standalone external payload image.
|
||||||
- Working example configuration and RBAC for both execution targets.
|
- Working example configuration and RBAC for both execution targets.
|
||||||
|
|
||||||
|
### verified
|
||||||
|
|
||||||
|
- `tightly_coupled_k8s_job` executed end to end on sandbox-cat-dat through the
|
||||||
|
platform `K8sRunLauncher` (run `1d8cb167-9fb8-4a34-a036-789eac381e13`), closing
|
||||||
|
readiness rows T6 and T7. Step outputs are written to the shared
|
||||||
|
`dagster-shared-pvc` by pinning `fs_io_manager`'s `base_dir`; `DAGSTER_HOME` set
|
||||||
|
through `step_k8s_config` is ignored, because the Dagster chart injects
|
||||||
|
`DAGSTER_HOME=/tmp/dagster` ahead of it.
|
||||||
|
- `loosely_coupled_k8s_job` reached `RUN_SUCCESS` on sandbox-cat-dat through the
|
||||||
|
standalone probe (run `cff9b348-bfc3-4ac1-ab51-a94892b8e3a0`), with four
|
||||||
|
external payload pods reporting over the pod-log message channel.
|
||||||
|
- Tightly coupled preflight evidence now checks the chart's actual
|
||||||
|
`DAGSTER_PG_PASSWORD` injection without exposing its value.
|
||||||
|
- Dagster UI screenshots cover the registered jobs, graph, code-configured
|
||||||
|
execution-target tags and a successful reference run.
|
||||||
|
- The platform deployment diagram includes the service and both integration
|
||||||
|
patterns.
|
||||||
|
|
||||||
### pending
|
### pending
|
||||||
|
|
||||||
- Publish the payload image to the container registry.
|
- Extend the project-level GitLab pipeline to publish the payload image as well
|
||||||
- End-to-end run of `loosely_coupled_k8s_job` against a cluster, and confirmation
|
as the code-location image.
|
||||||
of the Kubernetes rows in the readiness checklist.
|
|
||||||
- Screenshots of UI surfaces and integration-pattern diagrams.
|
|
||||||
- Platform architecture document update.
|
|
||||||
|
|||||||
4
LICENSE
4
LICENSE
@@ -1,3 +1,3 @@
|
|||||||
# EUROPEAN UNION PUBLIC LICENCE v. 1.2
|
# EUROPEAN UNION PUBLIC LICENSE v. 1.2
|
||||||
|
|
||||||
Refer to [licence description](https://eupl.eu/1.2/en/)
|
Refer to [license description](https://eupl.eu/1.2/en/)
|
||||||
20
README.md
20
README.md
@@ -14,7 +14,7 @@ actually run, and how does runtime information get back to the control plane?*
|
|||||||
| User guide | [documents/user-guide/distributed-execution-guide.md](documents/user-guide/distributed-execution-guide.md) | Complete |
|
| User guide | [documents/user-guide/distributed-execution-guide.md](documents/user-guide/distributed-execution-guide.md) | Complete |
|
||||||
| Readiness checklist | [documents/user-guide/readiness-checklist.md](documents/user-guide/readiness-checklist.md) | Complete |
|
| Readiness checklist | [documents/user-guide/readiness-checklist.md](documents/user-guide/readiness-checklist.md) | Complete |
|
||||||
| Tightly coupled reference | [src/distributed_execution/tightly_coupled/jobs.py](src/distributed_execution/tightly_coupled/jobs.py) | Runnable |
|
| Tightly coupled reference | [src/distributed_execution/tightly_coupled/jobs.py](src/distributed_execution/tightly_coupled/jobs.py) | Runnable |
|
||||||
| Loosely coupled reference | [src/distributed_execution/loosely_coupled/jobs.py](src/distributed_execution/loosely_coupled/jobs.py) | Runnable (subprocess verified) |
|
| Loosely coupled reference | [src/distributed_execution/loosely_coupled/jobs.py](src/distributed_execution/loosely_coupled/jobs.py) | Runnable and cluster-verified |
|
||||||
| External payload | [payload/work.py](payload/work.py) | Runnable |
|
| External payload | [payload/work.py](payload/work.py) | Runnable |
|
||||||
| Example configuration | [yaml/](yaml/) | Complete |
|
| Example configuration | [yaml/](yaml/) | Complete |
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ distributed-execution/
|
|||||||
│ ├── work.py
|
│ ├── work.py
|
||||||
│ ├── requirements.txt
|
│ ├── requirements.txt
|
||||||
│ └── Dockerfile
|
│ └── Dockerfile
|
||||||
├── documents/user-guide/ # AC1-AC4 documentation
|
├── documents/user-guide/ # Guide, checklist and requirement traceability
|
||||||
├── yaml/ # Working example configuration
|
├── yaml/ # Working example configuration
|
||||||
├── tests/
|
├── tests/
|
||||||
├── Dockerfile
|
├── Dockerfile
|
||||||
@@ -81,17 +81,17 @@ Both images build and have been smoke tested locally: the code location image
|
|||||||
loads its definitions, and the payload image contains `dagster_pipes` without
|
loads its definitions, and the payload image contains `dagster_pipes` without
|
||||||
`dagster` — check L11 in the readiness checklist.
|
`dagster` — check L11 in the readiness checklist.
|
||||||
|
|
||||||
[.gitea/workflows/docker-publish.yml](.gitea/workflows/docker-publish.yml) runs
|
Both must be tagged from the same commit. That shared tag is what keeps a code
|
||||||
the same two builds on every push to `main`, applies those checks as gates, and
|
location and the payload it dispatches on the same version, and nothing at
|
||||||
tags both images with the same short commit SHA — that shared tag is what keeps a
|
runtime checks the pairing — see the *Outstanding work* section for what the
|
||||||
code location and the payload it dispatches on the same version.
|
pipeline still has to learn.
|
||||||
|
|
||||||
## Status
|
## Status
|
||||||
|
|
||||||
Both execution targets are implemented. The tightly coupled jobs and the loosely
|
Both execution targets are implemented. Local variants are verified by the test
|
||||||
coupled **subprocess** transport are verified by the test suite. The loosely
|
suite, `tightly_coupled_k8s_job` has run end to end through the platform launcher,
|
||||||
coupled **Kubernetes** transport is implemented but has not yet been run against
|
and `loosely_coupled_k8s_job` has run end to end through the standalone cluster
|
||||||
a cluster; see the guide's *Outstanding work* section.
|
probe. See the guide and readiness checklist for the recorded evidence.
|
||||||
|
|
||||||
## Licence
|
## Licence
|
||||||
|
|
||||||
|
|||||||
@@ -5,12 +5,10 @@
|
|||||||
integration pattern for a Dagster workflow on the Simpl orchestration platform.
|
integration pattern for a Dagster workflow on the Simpl orchestration platform.
|
||||||
|
|
||||||
> **Document status.** Both setups are backed by runnable reference
|
> **Document status.** Both setups are backed by runnable reference
|
||||||
> implementations in this repository. The tightly coupled setup and the loosely
|
> implementations and verified end to end. The loosely coupled Kubernetes path
|
||||||
> coupled **subprocess** transport are verified end to end, including runs
|
> reached `RUN_SUCCESS` on sandbox-cat-dat on 2026-08-31; the tightly coupled
|
||||||
> launched from the Dagster UI — see [section 5.6](#56-what-a-verified-run-actually-produced).
|
> `k8s_job_executor` path reached `RUN_SUCCESS` through the platform launcher on
|
||||||
> The loosely coupled **Kubernetes** transport is implemented and reviewed but
|
> 2026-09-01. See the readiness checklist for the recorded evidence.
|
||||||
> has not yet been run against a cluster; statements specific to it are marked
|
|
||||||
> **NOT CLUSTER-VERIFIED**. See [Outstanding work](#8-outstanding-work).
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -68,7 +66,7 @@ pattern.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 2. AC1 — Choosing an execution target
|
## 2. Choosing an execution target and cluster setup
|
||||||
|
|
||||||
### 2.1 Choose tightly coupled when
|
### 2.1 Choose tightly coupled when
|
||||||
|
|
||||||
@@ -123,7 +121,7 @@ before it is run for the first time. Section 5.4 explains where each item lives.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 3. AC2 — Decision support
|
## 3. Decision support and cluster-configuration inputs
|
||||||
|
|
||||||
### 3.1 Side-by-side comparison
|
### 3.1 Side-by-side comparison
|
||||||
|
|
||||||
@@ -181,9 +179,134 @@ Use these as a fast triage. If several point the same way, that is your answer.
|
|||||||
succeed while reporting nothing. Two images to build, version and scan instead
|
succeed while reporting nothing. Two images to build, version and scan instead
|
||||||
of one.
|
of one.
|
||||||
|
|
||||||
|
### 3.4 Cluster-configuration inputs
|
||||||
|
|
||||||
|
Once the setup is chosen, the container cluster has to be described. The table
|
||||||
|
below is the full input surface, split into what a run cannot start without and
|
||||||
|
what only applies under a stated condition. "Mandatory" means the run fails, or
|
||||||
|
reports nothing, if the input is absent or wrong.
|
||||||
|
|
||||||
|
| Input | Tightly coupled | Loosely coupled | Notes |
|
||||||
|
|---|---|---|---|
|
||||||
|
| Cluster / kube context hosting the run worker | Mandatory | Mandatory | The launcher's cluster. Loosely coupled may dispatch to a *second* cluster |
|
||||||
|
| Namespace for run pods | Mandatory | Mandatory | Supplied by the code location's `DAGSTER_CONTAINER_CONTEXT`; the launcher's `job_namespace` is only a fallback |
|
||||||
|
| Code location image reference and tag | Mandatory | Mandatory | Never `latest`; check C3 |
|
||||||
|
| Executor selection | Mandatory | Mandatory | Bounds step granularity; loosely coupled it bounds only dispatch concurrency |
|
||||||
|
| Service account for run pods | Mandatory | Mandatory | Must have `automountServiceAccountToken: true` |
|
||||||
|
| Run-pod egress to the metadata database | **Mandatory** | Not applicable | The pod that writes run events |
|
||||||
|
| Namespace for step pods | Conditional — `k8s_job_executor` only | Not applicable | Defaults to the run pod's namespace |
|
||||||
|
| RBAC to create and watch Jobs | Conditional — `k8s_job_executor` only | **Mandatory**, in the payload namespace | Same verbs, different namespace |
|
||||||
|
| Shared RWX volume plus an I/O manager `base_dir` under it | Conditional — `k8s_job_executor` only | Optional | Without it step pods cannot read each other's outputs |
|
||||||
|
| Per-step resource requests and limits | Optional | Optional | Multiply by step or dispatch concurrency |
|
||||||
|
| Payload image reference and tag | Not applicable | **Mandatory** | Must share the code location's commit tag |
|
||||||
|
| Namespace for payload workloads | Not applicable | **Mandatory** | May be in another cluster or trust boundary |
|
||||||
|
| Message channel and its reader | Not applicable | **Mandatory** | Pod log stream by default; RBAC on `pods/log` *is* the channel |
|
||||||
|
| Payload wait timeout | Not applicable | Optional | Defaults to 24 h — lower it so scheduling failures surface |
|
||||||
|
| Vault role and secret paths | Conditional — if the workflow reads secrets | Conditional — launching pod only | Payloads should receive only `extras` and explicit `env` |
|
||||||
|
| Object-storage endpoint and credentials | Conditional — if the workflow uses S3 | Conditional — if the *payload* uses S3 | |
|
||||||
|
| Image pull secret | Conditional — non-anonymous registry | Conditional — non-anonymous registry | Applies to the SA that runs the pod, which for dispatched payload Jobs is `default` |
|
||||||
|
|
||||||
|
### 3.5 Minimum input set
|
||||||
|
|
||||||
|
The list below is the reusable baseline: the smallest set of values a team has to
|
||||||
|
agree on before a workflow can be configured against a cluster. Record it once
|
||||||
|
per workflow, in the workflow's own repository, and carry it into whatever
|
||||||
|
configuration format the team already uses.
|
||||||
|
|
||||||
|
**Both setups**
|
||||||
|
|
||||||
|
1. `cluster` — the cluster the run worker lands in.
|
||||||
|
2. `run_namespace` — namespace for run pods.
|
||||||
|
3. `code_location_image` — image reference including an immutable tag.
|
||||||
|
4. `executor` — executor name plus its concurrency bound.
|
||||||
|
5. `service_account` — the identity run pods assume.
|
||||||
|
|
||||||
|
**Tightly coupled adds**
|
||||||
|
|
||||||
|
6. `metadata_db` — host and port the run and step pods must reach.
|
||||||
|
7. `step_namespace` — only when `k8s_job_executor` is used.
|
||||||
|
8. `shared_output_path` — RWX mount path, and the I/O manager `base_dir` pinned
|
||||||
|
under it, again only for `k8s_job_executor`.
|
||||||
|
|
||||||
|
**Loosely coupled adds**
|
||||||
|
|
||||||
|
6. `payload_image` — image reference sharing the code location's commit tag.
|
||||||
|
7. `payload_namespace` — where dispatched workloads are created; may be in
|
||||||
|
another cluster.
|
||||||
|
8. `message_channel` — the reader in use, and the RBAC verb that carries it.
|
||||||
|
|
||||||
|
This guide deliberately does **not** prescribe a configuration schema or key
|
||||||
|
names. The names above are descriptive labels for the values, not a required
|
||||||
|
format; the examples in section 3.6 express the same baseline in two different
|
||||||
|
shapes, and both are correct.
|
||||||
|
|
||||||
|
### 3.6 Worked input examples
|
||||||
|
|
||||||
|
The reference configuration in [yaml/](../../yaml) shows the baseline expressed
|
||||||
|
in the formats each setup already uses. Neither is normative.
|
||||||
|
|
||||||
|
**Tightly coupled** — the inputs land in Helm values and in the job's executor
|
||||||
|
config, because that is where the platform chart and Dagster expect them:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# yaml/tightly-coupled/values-run-launcher.yaml (shape, not a fixed schema)
|
||||||
|
dagster:
|
||||||
|
runLauncher:
|
||||||
|
type: K8sRunLauncher
|
||||||
|
config:
|
||||||
|
k8sRunLauncher:
|
||||||
|
jobNamespace: dagster # run_namespace
|
||||||
|
failPodOnRunFailure: true
|
||||||
|
runK8sConfig:
|
||||||
|
containerConfig:
|
||||||
|
env: # metadata_db, S3 and Vault reachability
|
||||||
|
- name: S3_ENDPOINT_URL
|
||||||
|
value: https://s3.dev.simpl-europe.eu
|
||||||
|
```
|
||||||
|
|
||||||
|
```python
|
||||||
|
# step_namespace, shared_output_path and the executor travel with the job
|
||||||
|
tightly_coupled_k8s_job = distributed_execution_reference.to_job(
|
||||||
|
executor_def=k8s_job_executor,
|
||||||
|
resource_defs={"io_manager": fs_io_manager.configured({"base_dir": SHARED_IO_BASE_DIR})},
|
||||||
|
config={"execution": {"config": {"step_k8s_config": STEP_K8S_CONFIG}}},
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Loosely coupled** — the same baseline, but the cluster-facing half is the
|
||||||
|
payload image and its namespace. Here they are environment values set on both the
|
||||||
|
code location and the run launcher, because the dispatching pod is a run pod:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# yaml/loosely-coupled/values-pipes-payload.yaml (shape, not a fixed schema)
|
||||||
|
dagster:
|
||||||
|
dagster-user-deployments:
|
||||||
|
deployments:
|
||||||
|
- name: distributed-execution
|
||||||
|
env:
|
||||||
|
- name: PIPES_PAYLOAD_IMAGE # payload_image, tag-locked
|
||||||
|
value: <registry>/distributed-execution/payload:0.0.0
|
||||||
|
- name: PIPES_PAYLOAD_NAMESPACE # payload_namespace
|
||||||
|
value: dagster
|
||||||
|
```
|
||||||
|
|
||||||
|
```python
|
||||||
|
PAYLOAD_IMAGE = os.environ.get("PIPES_PAYLOAD_IMAGE", ...)
|
||||||
|
PAYLOAD_NAMESPACE = os.environ.get("PIPES_PAYLOAD_NAMESPACE", "dagster")
|
||||||
|
```
|
||||||
|
|
||||||
|
The `message_channel` input has no key in either file. The default reader is the
|
||||||
|
pod log stream, so it is configured by granting `pods/log` in
|
||||||
|
[yaml/loosely-coupled/rbac-pipes-dispatch.yaml](../../yaml/loosely-coupled/rbac-pipes-dispatch.yaml).
|
||||||
|
An input can be mandatory and still not be a configuration field.
|
||||||
|
|
||||||
|
Note what is absent from the loosely coupled example: no metadata database, no
|
||||||
|
Vault role, no object-storage credentials. Those inputs are not optional there —
|
||||||
|
they do not exist, which is the operational consequence of the choice.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 4. AC3 — Readiness checks
|
## 4. Readiness checks
|
||||||
|
|
||||||
Pre-run validation items, their expected evidence, and the symptoms and
|
Pre-run validation items, their expected evidence, and the symptoms and
|
||||||
corrections for common misconfigurations are maintained separately, in
|
corrections for common misconfigurations are maintained separately, in
|
||||||
@@ -191,7 +314,7 @@ corrections for common misconfigurations are maintained separately, in
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 5. AC4 — Configuring execution-target linkage in code
|
## 5. Configuring execution-target linkage in code
|
||||||
|
|
||||||
### 5.1 Configuration constructs
|
### 5.1 Configuration constructs
|
||||||
|
|
||||||
@@ -231,12 +354,18 @@ tightly_coupled_local_job = distributed_execution_reference.to_job(
|
|||||||
```python
|
```python
|
||||||
tightly_coupled_k8s_job = distributed_execution_reference.to_job(
|
tightly_coupled_k8s_job = distributed_execution_reference.to_job(
|
||||||
name="tightly_coupled_k8s_job",
|
name="tightly_coupled_k8s_job",
|
||||||
executor_def=k8s_job_executor.configured(
|
executor_def=k8s_job_executor,
|
||||||
{
|
resource_defs={
|
||||||
|
"io_manager": fs_io_manager.configured({"base_dir": SHARED_IO_BASE_DIR})
|
||||||
|
},
|
||||||
|
config={
|
||||||
|
"execution": {
|
||||||
|
"config": {
|
||||||
"image_pull_policy": "IfNotPresent",
|
"image_pull_policy": "IfNotPresent",
|
||||||
"step_k8s_config": STEP_K8S_CONFIG,
|
"step_k8s_config": STEP_K8S_CONFIG,
|
||||||
}
|
}
|
||||||
),
|
}
|
||||||
|
},
|
||||||
tags={**COMMON_TAGS, "executor": "k8s_job"},
|
tags={**COMMON_TAGS, "executor": "k8s_job"},
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
@@ -251,6 +380,22 @@ operationally:
|
|||||||
[yaml/tightly-coupled/rbac-step-executor.yaml](../../yaml/tightly-coupled/rbac-step-executor.yaml).
|
[yaml/tightly-coupled/rbac-step-executor.yaml](../../yaml/tightly-coupled/rbac-step-executor.yaml).
|
||||||
- Per-step resource requests apply per pod, so the aggregate request for a
|
- Per-step resource requests apply per pod, so the aggregate request for a
|
||||||
fan-out step is the per-step request multiplied by concurrency.
|
fan-out step is the per-step request multiplied by concurrency.
|
||||||
|
- **Step outputs must land on storage every step pod can read.** With the default
|
||||||
|
filesystem I/O manager each pod writes to its own container filesystem, so a
|
||||||
|
downstream step opens a path that does not exist there. `STEP_K8S_CONFIG` mounts
|
||||||
|
the RWX `dagster-shared-pvc` at `/dagster/shared`, and the job pins
|
||||||
|
`fs_io_manager`'s `base_dir` underneath it.
|
||||||
|
- Pin `base_dir` directly rather than relying on `DAGSTER_HOME`. The default
|
||||||
|
`base_dir` is `$DAGSTER_HOME/storage`, but the Dagster chart already injects
|
||||||
|
`DAGSTER_HOME=/tmp/dagster` into the step container; a second entry appended by
|
||||||
|
`step_k8s_config` does not displace it, so the override is silently ignored and
|
||||||
|
outputs keep going to `/tmp/dagster/storage`.
|
||||||
|
|
||||||
|
The executor's defaults go through `config=` rather than
|
||||||
|
`k8s_job_executor.configured(...)`. `.configured()` collapses the executor's
|
||||||
|
config schema to `Any`, which makes a run-config `execution:` block accepted and
|
||||||
|
then discarded, and makes `job_image` and `job_namespace` impossible to supply at
|
||||||
|
launch time.
|
||||||
|
|
||||||
The evidence that the switch took effect is in `summarise_results` output
|
The evidence that the switch took effect is in `summarise_results` output
|
||||||
metadata, and the two fields say different things:
|
metadata, and the two fields say different things:
|
||||||
@@ -378,10 +523,12 @@ empty result. If your cluster's logging setup makes that transport unreliable,
|
|||||||
switch to an object-storage message reader, which needs a bucket plus
|
switch to an object-storage message reader, which needs a bucket plus
|
||||||
credentials on both sides.
|
credentials on both sides.
|
||||||
|
|
||||||
> **NOT CLUSTER-VERIFIED.** The Kubernetes transport above is implemented and
|
> **CLUSTER-VERIFIED 2026-08-31.** Run `cff9b348…` of `loosely_coupled_k8s_job`
|
||||||
> its RBAC and configuration are recorded, but it has not yet been run against a
|
> reached `RUN_SUCCESS` on sandbox-cat-dat. Four payload Jobs were created, one
|
||||||
> Simpl cluster. The subprocess transport, which exercises the identical payload
|
> per work unit, and `contributing_hosts` held four distinct payload pod names —
|
||||||
> and the identical message-parsing path, is verified by the test suite.
|
> so the work demonstrably ran off the orchestrator. The payload's log lines
|
||||||
|
> reached the run log, which is the pod log stream serving as the message
|
||||||
|
> channel exactly as described above.
|
||||||
|
|
||||||
### 5.4 Where setup selection is persisted
|
### 5.4 Where setup selection is persisted
|
||||||
|
|
||||||
@@ -395,7 +542,10 @@ setting. There is no UI control that switches a workflow between the two pattern
|
|||||||
| `yaml/tightly-coupled/values-run-launcher.yaml` | Run launcher type, namespace, pod env |
|
| `yaml/tightly-coupled/values-run-launcher.yaml` | Run launcher type, namespace, pod env |
|
||||||
| `yaml/tightly-coupled/rbac-step-executor.yaml` | Permissions required by `k8s_job_executor` |
|
| `yaml/tightly-coupled/rbac-step-executor.yaml` | Permissions required by `k8s_job_executor` |
|
||||||
| `yaml/loosely-coupled/values-pipes-payload.yaml` | Payload image reference and target namespace |
|
| `yaml/loosely-coupled/values-pipes-payload.yaml` | Payload image reference and target namespace |
|
||||||
|
| `yaml/sandbox/values-sandbox-gitea.yaml` | Sandbox registry coordinates, pull secret, and the SHA both images share |
|
||||||
| `yaml/loosely-coupled/rbac-pipes-dispatch.yaml` | Permissions required by the dispatching pod |
|
| `yaml/loosely-coupled/rbac-pipes-dispatch.yaml` | Permissions required by the dispatching pod |
|
||||||
|
| `yaml/loosely-coupled/probe-pipes-k8s.yaml` | Standalone cluster probe for the pipes transport (checklist L4–L9) |
|
||||||
|
| `yaml/sandbox/probe-pipes-k8s-sandbox.yaml` | The same probe for sandbox-cat-dat, where project-scoped access forbids creating namespaces and RBAC |
|
||||||
| `yaml/values-dagster-distributed-execution.yaml` | Code location image and entry point |
|
| `yaml/values-dagster-distributed-execution.yaml` | Code location image and entry point |
|
||||||
|
|
||||||
The Launchpad can override *run configuration* — op config, resource config, tags
|
The Launchpad can override *run configuration* — op config, resource config, tags
|
||||||
@@ -478,6 +628,32 @@ on a cluster it is what distinguishes `k8s_job_executor` from
|
|||||||
holds the namespace the run pod landed in, which is the placement half of the
|
holds the namespace the run pod landed in, which is the placement half of the
|
||||||
execution target.
|
execution target.
|
||||||
|
|
||||||
|
### 5.7 Dagster UI reference
|
||||||
|
|
||||||
|
The screenshots below were captured from the local reference service on
|
||||||
|
2026-09-02. They show the surfaces participants use to inspect job linkage and
|
||||||
|
run evidence. Cluster placement is evidenced separately by the sandbox run IDs
|
||||||
|
in the readiness checklist.
|
||||||
|
|
||||||
|
All five reference jobs are registered under one code location:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
The job overview exposes the graph whose executor or dispatch op defines the
|
||||||
|
integration pattern:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
The Launchpad shows that `execution_target` and `executor` are job tags persisted
|
||||||
|
by code configuration, not a separate runtime-only selector:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
A successful local run displays the step events and final status used alongside
|
||||||
|
output metadata as retained evidence:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 6. Upstream documentation
|
## 6. Upstream documentation
|
||||||
@@ -499,22 +675,59 @@ execution target.
|
|||||||
|
|
||||||
## 8. Outstanding work
|
## 8. Outstanding work
|
||||||
|
|
||||||
Tracked under SIMPL-30451.
|
Tracked under SIMPL-30451 and SIMPL-30787.
|
||||||
|
|
||||||
| Item | AC | Status |
|
| Item | Status |
|
||||||
|
|---|---|
|
||||||
|
| Execution-target choices, prerequisites, workflow-level documentation | Complete |
|
||||||
|
| Comparison, environment-fit indicators, trade-offs | Complete |
|
||||||
|
| Cluster-configuration inputs, mandatory vs optional, minimum input set | Complete |
|
||||||
|
| Readiness checklist and evidence mapping | Complete; both Kubernetes paths cluster-verified |
|
||||||
|
| Misconfiguration symptoms and corrections | Complete; corrected with observed cluster failure modes |
|
||||||
|
| Configuration constructs and persistence | Complete |
|
||||||
|
| Before-and-after example, tightly coupled | Complete |
|
||||||
|
| Before-and-after example, switching to loosely coupled | Complete |
|
||||||
|
| Runnable tightly coupled reference implementations | Complete |
|
||||||
|
| Runnable loosely coupled reference implementation | Complete (subprocess and Kubernetes transports both verified) |
|
||||||
|
| Both images build; payload image passes the isolation check (L11) | Complete |
|
||||||
|
| Locally runnable jobs launched from the Dagster UI, evidence recorded in section 5.6 | Complete |
|
||||||
|
| Payload image published to a container registry | Complete on the sandbox Gitea registry; the GitLab registry still pending |
|
||||||
|
| GitLab pipeline builds both images | **Pending** — the shared `ds.gitlab-ci.yml` template builds one image from the root Dockerfile |
|
||||||
|
| End-to-end run of `loosely_coupled_k8s_job` on a cluster | Complete — sandbox-cat-dat, 2026-08-31, run `cff9b348…`; see the readiness checklist |
|
||||||
|
| `distributed-execution` registered as a code location on a platform Dagster | Complete — tightly coupled run `1d8cb167…` launched through the platform webserver |
|
||||||
|
| Screenshots of UI surfaces | Complete — job list, graph, Launchpad linkage and successful run captured in section 5.7 |
|
||||||
|
| Platform architecture document update | Complete — root `deployment_diagram.md` includes the service and both runtime-information paths |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. Requirement traceability
|
||||||
|
|
||||||
|
The sections above are organised by subject, not by ticket. Two stories share
|
||||||
|
this material; the mapping below is authoritative for both.
|
||||||
|
|
||||||
|
### SIMPL-30787 — defining the execution container cluster
|
||||||
|
|
||||||
|
| AC | Requirement | Where it is met |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| Execution-target choices, prerequisites, workflow-level documentation | AC1 | Complete |
|
| AC1 | Prerequisites for both setups | Section 2.3 |
|
||||||
| Comparison, environment-fit indicators, trade-offs | AC2 | Complete |
|
| AC1 | What must be documented before execution | Section 2.4 |
|
||||||
| Readiness checklist and evidence mapping | AC3 | Complete; K8s pipes checks not cluster-verified |
|
| AC1 | Where cluster-runtime connectivity is required, where decoupled reporting is expected | Sections 1.2 and 2.3; the asymmetry is drawn in the section 1.2 diagram |
|
||||||
| Misconfiguration symptoms and corrections | AC3 | Complete; K8s pipes symptoms not cluster-verified |
|
| AC2 | Mandatory vs optional inputs per setup | Section 3.4 |
|
||||||
| Configuration constructs and persistence | AC4 | Complete |
|
| AC2 | Examples for both setups, no fixed config naming model | Section 3.6, with the closing note in 3.5 |
|
||||||
| Before-and-after example, tightly coupled | AC4 | Complete |
|
| AC2 | Reusable minimum input set | Section 3.5 |
|
||||||
| Before-and-after example, switching to loosely coupled | AC4 | Complete |
|
| AC3 | Checklist separates tightly from loosely coupled checks | [readiness-checklist.md](readiness-checklist.md) sections 2 and 3; section 1 holds the checks common to both |
|
||||||
| Runnable tightly coupled reference implementations | AC4 | Complete |
|
| AC3 | Each item mapped to expected evidence | The *Expected evidence* column of every checklist table |
|
||||||
| Runnable loosely coupled reference implementation | AC4 | Complete (subprocess verified, K8s not cluster-run) |
|
| AC4 | Configuration constructs attaching the pattern to a workflow | Section 5.1 |
|
||||||
| Both images build; payload image passes the isolation check (L11) | Tech details | Complete |
|
| AC4 | Worked before-and-after example across setups | Sections 5.2 and 5.3 |
|
||||||
| Locally runnable jobs launched from the Dagster UI, evidence recorded in section 5.6 | Tech details | Complete |
|
| AC4 | At least one runnable reference implementation per setup | Section 5.5 — three tightly coupled, two loosely coupled |
|
||||||
| Payload image published to a container registry | Tech details | Complete on the sandbox Gitea registry; the GitLab registry still pending |
|
| AC4 | Selection persisted in configuration artifacts, not runtime-only | Section 5.4 |
|
||||||
| End-to-end run of `loosely_coupled_k8s_job` on a cluster | Tech details | **Pending** |
|
| Tech | Diagrams, screenshots, working config files, upstream links | Sections 1.2, 5.7, [yaml/](../../yaml), section 6 |
|
||||||
| Screenshots of UI surfaces | Tech details | **Pending** — needs a deployed platform instance, not a local dev server |
|
|
||||||
| Platform architecture document update | Tech details | **Pending** |
|
### SIMPL-30451 — execution targets and integration patterns
|
||||||
|
|
||||||
|
| AC | Subject | Where it is met |
|
||||||
|
|---|---|---|
|
||||||
|
| AC1 | Choosing an execution target | Section 2 |
|
||||||
|
| AC2 | Decision support | Sections 3.1 to 3.3 |
|
||||||
|
| AC3 | Readiness checks | Section 4 and the readiness checklist |
|
||||||
|
| AC4 | Linkage configured in code | Section 5 |
|
||||||
|
|||||||
BIN
documents/user-guide/images/distributed-execution-job-graph.png
Normal file
BIN
documents/user-guide/images/distributed-execution-job-graph.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 108 KiB |
BIN
documents/user-guide/images/distributed-execution-job-list.png
Normal file
BIN
documents/user-guide/images/distributed-execution-job-list.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 78 KiB |
BIN
documents/user-guide/images/distributed-execution-launchpad.png
Normal file
BIN
documents/user-guide/images/distributed-execution-launchpad.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 114 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 155 KiB |
@@ -1,17 +1,20 @@
|
|||||||
# Distributed Execution: Readiness Checklist
|
# Distributed Execution: Readiness Checklist
|
||||||
|
|
||||||
Pre-run validation for a workflow's execution target. Companion to the
|
Pre-run validation for a workflow's execution target. Companion to the
|
||||||
[user guide](distributed-execution-guide.md); this document covers AC3.
|
[user guide](distributed-execution-guide.md); this document is the validation
|
||||||
|
checklist required by SIMPL-30451 AC3 and SIMPL-30787 AC3. Section 1 holds the
|
||||||
|
checks common to both setups, section 2 the tightly coupled checks and section 3
|
||||||
|
the loosely coupled ones; every item states the evidence that proves it.
|
||||||
|
|
||||||
Run these checks **before the first execution** of a workflow, and again after any
|
Run these checks **before the first execution** of a workflow, and again after any
|
||||||
change to the run launcher, the executor, the target namespace or the code
|
change to the run launcher, the executor, the target namespace or the code
|
||||||
location image.
|
location image.
|
||||||
|
|
||||||
> **NOT CLUSTER-VERIFIED.** Checks L4–L9 and the Kubernetes rows of section 4.3
|
> **Both Kubernetes paths are cluster-verified.** L4–L10 were cleared on
|
||||||
> are derived from the implemented reference but have not yet been run against a
|
> sandbox-cat-dat on 2026-08-31. The tightly coupled `k8s_job_executor` path
|
||||||
> Simpl cluster. Checks L1–L3, L10 and L11, which exercise the payload contract,
|
> reached `RUN_SUCCESS` through the platform launcher on 2026-09-01. Checks
|
||||||
> the message-parsing path, per-unit dispatch and image-level isolation, are
|
> L1–L3 and L11, which exercise the payload contract, message parsing and image
|
||||||
> verified locally.
|
> isolation, are also verified locally. See [section 2.1](#21-sandbox-state-2026-08-31).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -23,14 +26,14 @@ location image.
|
|||||||
| C2 | Jobs are registered | Dagster UI → **Jobs** | The jobs listed in the guide's section 5.5 appear under the code location |
|
| C2 | Jobs are registered | Dagster UI → **Jobs** | The jobs listed in the guide's section 5.5 appear under the code location |
|
||||||
| C3 | Image tag matches the intended release | `kubectl -n dagster get deploy -l dagster/code-location=distributed-execution -o jsonpath='{.items[*].spec.template.spec.containers[*].image}'` | Tag equals the version in `pipeline.variables.sh`; never `latest` |
|
| C3 | Image tag matches the intended release | `kubectl -n dagster get deploy -l dagster/code-location=distributed-execution -o jsonpath='{.items[*].spec.template.spec.containers[*].image}'` | Tag equals the version in `pipeline.variables.sh`; never `latest` |
|
||||||
| C4 | Image architecture matches the nodes | `docker manifest inspect <image>` | Includes `linux/amd64`; a manifest with only `linux/arm64` produces `no match for platform` at pull time |
|
| C4 | Image architecture matches the nodes | `docker manifest inspect <image>` | Includes `linux/amd64`; a manifest with only `linux/arm64` produces `no match for platform` at pull time |
|
||||||
| C5 | Run launcher type is as intended | `kubectl -n dagster get cm dagster-instance -o yaml` | `run_launcher` block shows `K8sRunLauncher` and the expected `job_namespace` |
|
| C5 | Run launcher type is as intended | `kubectl -n <namespace> get cm dagster-instance -o yaml` | `run_launcher` block shows `K8sRunLauncher`. Note that `job_namespace` here is only a default — a code location's `DAGSTER_CONTAINER_CONTEXT` overrides it, so read that too before concluding where run pods land |
|
||||||
| C6 | Target namespace exists and is schedulable | `kubectl get ns <namespace>` and `kubectl -n <namespace> get resourcequota` | Namespace is `Active`; remaining quota exceeds the job's aggregate requests |
|
| C6 | Target namespace exists and is schedulable | `kubectl get ns <namespace>` and `kubectl -n <namespace> get resourcequota` | Namespace is `Active`; remaining quota exceeds the job's aggregate requests. Also confirm the launcher's `instance_config_map`, `postgres_password_secret` and any PVC volumes exist **in the namespace run pods actually use** — these references do not cross namespaces (see section 2.1) |
|
||||||
|
|
||||||
## 2. Tightly coupled checks
|
## 2. Tightly coupled checks
|
||||||
|
|
||||||
| # | Check | How to verify | Expected evidence |
|
| # | Check | How to verify | Expected evidence |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| T1 | Run pod reaches the metadata database | Launch `tightly_coupled_in_process_job` | Run reaches `SUCCESS`; `report_execution_target` output metadata lists `DAGSTER_POSTGRES_HOST`, `DAGSTER_POSTGRES_USER` and `DAGSTER_POSTGRES_DB` under `env_vars_present`, and `env_vars_missing` is empty |
|
| T1 | Run pod reaches the metadata database | Launch `tightly_coupled_in_process_job` | Run reaches `SUCCESS`; `report_execution_target` metadata lists `DAGSTER_PG_PASSWORD` under `env_vars_present` without exposing its value, and `env_vars_missing` is empty. Successful step startup is the connectivity proof because the step loads run state from Postgres before executing the op |
|
||||||
| T2 | Vault injection works | Same run; inspect the run pod | `kubectl -n dagster describe pod <run-pod>` shows the `vault-env` init container completed; no `vault:` literal remains in the process environment |
|
| T2 | Vault injection works | Same run; inspect the run pod | `kubectl -n dagster describe pod <run-pod>` shows the `vault-env` init container completed; no `vault:` literal remains in the process environment |
|
||||||
| T3 | Object storage is reachable | Same run, if the workflow uses S3 | No `EndpointConnectionError` in run logs; `S3_ENDPOINT_URL` present in `env_vars_present` |
|
| T3 | Object storage is reachable | Same run, if the workflow uses S3 | No `EndpointConnectionError` in run logs; `S3_ENDPOINT_URL` present in `env_vars_present` |
|
||||||
| T4 | Multiprocess fan-out actually fans out | Launch `tightly_coupled_local_job` | Run succeeds; `summarise_results` metadata shows one entry per unit in `contributing_workers` and a single entry in `contributing_hosts` — separate processes, same machine |
|
| T4 | Multiprocess fan-out actually fans out | Launch `tightly_coupled_local_job` | Run succeeds; `summarise_results` metadata shows one entry per unit in `contributing_workers` and a single entry in `contributing_hosts` — separate processes, same machine |
|
||||||
@@ -39,6 +42,154 @@ location image.
|
|||||||
| T7 | Step pod egress is permitted | Same run | Steps do not hang in `STARTING`; run logs contain no connection timeouts to port 5432 |
|
| T7 | Step pod egress is permitted | Same run | Steps do not hang in `STARTING`; run logs contain no connection timeouts to port 5432 |
|
||||||
| T8 | Failure surfaces as a pod failure | Force a step failure in a scratch namespace | `failPodOnRunFailure: true` is set, and the step pod reports `Failed` rather than `Completed` |
|
| T8 | Failure surfaces as a pod failure | Force a step failure in a scratch namespace | `failPodOnRunFailure: true` is set, and the step pod reports `Failed` rather than `Completed` |
|
||||||
|
|
||||||
|
### 2.1 Sandbox state, 2026-08-31
|
||||||
|
|
||||||
|
The T checks were assessed against sandbox-cat-dat by reading the live
|
||||||
|
`dagster-instance` ConfigMap in `dataprovider01` and by running T1, T4, T6 and T7
|
||||||
|
from pods there.
|
||||||
|
|
||||||
|
What the configuration shows:
|
||||||
|
|
||||||
|
| # | Finding |
|
||||||
|
|---|---|
|
||||||
|
| C5 | `run_launcher` is `K8sRunLauncher`; `job_namespace: dagster` is the default, overridden per code location to `dataprovider01` |
|
||||||
|
| T2 | Vault injection is configured — `pod_template_spec_metadata` carries the banzaicloud annotations with role `sandbox-cat-dat-role` |
|
||||||
|
| T3 | `S3_ENDPOINT_URL` is `https://s3.sandbox-cat-dat.simpl-europe.eu`, with access keys injected from Vault |
|
||||||
|
| T5 | Passes. `dagster-role`, bound to `dagster-svc-account`, grants `batch/jobs` with create, delete, get, list, patch, update and watch |
|
||||||
|
| T8 | `fail_pod_on_run_failure: true` is set |
|
||||||
|
|
||||||
|
**T1 and T4 were executed on 2026-08-31** from a pod in `dataprovider01`
|
||||||
|
(`yaml/sandbox/probe-tightly-coupled-sandbox.yaml`), using a local SQLite
|
||||||
|
instance rather than the platform's Postgres.
|
||||||
|
|
||||||
|
| # | Result |
|
||||||
|
|---|---|
|
||||||
|
| T1 | Reachability **passes** — `check_tcp_reachable('pg-cluster.common01.svc.cluster.local', 5432)` returned `passed: True`. The env-var half of the check does not hold; see below |
|
||||||
|
| T4 | **Passes.** `tightly_coupled_local_job` reached `RUN_SUCCESS` with `contributing_hosts: ['distexec-tc-probe-hbdfl']` — one entry — and four distinct PIDs in `contributing_workers`. Separate processes, same machine, exactly as the row predicts |
|
||||||
|
|
||||||
|
`tightly_coupled_in_process_job` also succeeded, reporting a single worker.
|
||||||
|
|
||||||
|
### T1's env-var check and platform contract
|
||||||
|
|
||||||
|
The run emitted:
|
||||||
|
|
||||||
|
> Orchestration runtime env vars not visible to this process:
|
||||||
|
> `DAGSTER_POSTGRES_HOST`, `DAGSTER_POSTGRES_USER`, `DAGSTER_POSTGRES_DB`.
|
||||||
|
> Expected for a loosely coupled target; a misconfiguration for a tightly coupled one.
|
||||||
|
|
||||||
|
That warning was a false positive on a **correctly configured** platform run
|
||||||
|
pod. The chart does not set those variables: it injects `DAGSTER_PG_PASSWORD`
|
||||||
|
from `dagster-postgresql-secret` and stores host, user and database in
|
||||||
|
`dagster.yaml`. The reference check now tests for `DAGSTER_PG_PASSWORD` and
|
||||||
|
reports only its name, never its value. Database reachability is evidenced by
|
||||||
|
successful step startup: a tightly coupled step must load its run state from
|
||||||
|
the configured Dagster instance before `report_execution_target` can execute.
|
||||||
|
|
||||||
|
### T6 and T7, executed 2026-08-31
|
||||||
|
|
||||||
|
Running them needed three things the earlier attempt lacked: dagster pinned to
|
||||||
|
1.12.8 to match the control plane, so writing to the live `dataprovider01_dagster`
|
||||||
|
could not trigger a migration; step outputs moved onto the RWX
|
||||||
|
`dagster-shared-pvc`, because the default I/O manager writes them under
|
||||||
|
`$DAGSTER_HOME/storage` and each step pod otherwise gets its own empty volume;
|
||||||
|
and `automount_service_account_token: true` in `step_k8s_config`, because
|
||||||
|
`dagster-svc-account` disables it by default. The probe is
|
||||||
|
`yaml/sandbox/probe-k8s-executor-sandbox.yaml`; the run is
|
||||||
|
`d05c736a-8ec7-4e59-8cb0-9cb238db40dc`.
|
||||||
|
|
||||||
|
| # | Result |
|
||||||
|
|---|---|
|
||||||
|
| T6 | **Passes.** Six Jobs labelled `dagster/job=tightly_coupled_k8s_job` were created, one per step, each in its own pod |
|
||||||
|
| T7 | **Passes.** No step hung in `STARTING` and no step reported a connection timeout to port 5432. Every step pod opened the platform Postgres itself — the outputs and inputs below were all recorded through it |
|
||||||
|
|
||||||
|
Four steps executed and succeeded: `generate_work_units` (four dynamic outputs),
|
||||||
|
`report_execution_target`, and `process_work_unit[unit_0]` and `[unit_1]`, each
|
||||||
|
loading its input from the shared volume that a different pod wrote.
|
||||||
|
|
||||||
|
**The run then failed, and `summarise_results` never started.** The cause is a
|
||||||
|
property of the probe, not of the code or the platform:
|
||||||
|
|
||||||
|
> `Detected run worker status UNKNOWN: DagsterK8sUnrecoverableAPIError … jobs.batch`
|
||||||
|
> `"dagster-run-d05c736a-…" is forbidden: User "system:serviceaccount:dataprovider01:`
|
||||||
|
> `dagster-svc-account" cannot get resource "jobs/status" … in the namespace "dagster"`
|
||||||
|
|
||||||
|
Run monitoring polls for a run worker Job named `dagster-run-<run-id>`. The probe
|
||||||
|
starts the run with `dagster job execute` from a hand-rolled Job, so no such
|
||||||
|
object exists; and with no launcher-supplied container context the monitor looked
|
||||||
|
in the launcher's default namespace, `dagster`, where `dagster-svc-account` holds
|
||||||
|
no rights. The 403 turned *absent* into *unknown*, and the monitor failed the run
|
||||||
|
at its first poll. `process_work_unit[unit_2]` and `[unit_3]` had their pods
|
||||||
|
started already; both logged `Skipping step execution … since the run is in status
|
||||||
|
DagsterRunStatus.FAILURE` and exited 0 — which is why all six Jobs read `Complete`
|
||||||
|
while only four steps ran.
|
||||||
|
|
||||||
|
A run submitted the normal way, through the webserver to `K8sRunLauncher`, gets a
|
||||||
|
`dagster-run-<run-id>` Job in `dataprovider01` and is not exposed to this. Closing
|
||||||
|
T6/T7 end to end, including `summarise_results`, needs the code location
|
||||||
|
registered on the platform Dagster.
|
||||||
|
|
||||||
|
### T6 and T7 closed end to end, 2026-09-01
|
||||||
|
|
||||||
|
With the code location registered on the platform Dagster,
|
||||||
|
`tightly_coupled_k8s_job` was launched from the webserver and reached
|
||||||
|
`RUN_SUCCESS` as run `1d8cb167-9fb8-4a34-a036-789eac381e13`. `K8sRunLauncher`
|
||||||
|
created `dagster-run-1d8cb167-…` in `dataprovider01`, `K8sStepHandler` created one
|
||||||
|
`dagster-step-…` Job per step, and every step — including `summarise_results` —
|
||||||
|
completed. No hand-rolled probe, no run-monitoring 403.
|
||||||
|
|
||||||
|
**The last thing in the way was where step outputs are written.** Two earlier
|
||||||
|
attempts failed on
|
||||||
|
`FileNotFoundError: /tmp/dagster/storage/<run-id>/generate_work_units/result/unit_0`,
|
||||||
|
with every step pod using its own container filesystem. Mounting
|
||||||
|
`dagster-shared-pvc` into the step pods was necessary but not sufficient: setting
|
||||||
|
`DAGSTER_HOME` through `step_k8s_config` does not take effect, because the Dagster
|
||||||
|
chart already injects `DAGSTER_HOME=/tmp/dagster` and the appended second entry
|
||||||
|
does not displace the first. The fix is to bypass `DAGSTER_HOME` and pin the I/O
|
||||||
|
manager instead — `fs_io_manager.configured({"base_dir": SHARED_IO_BASE_DIR})` on
|
||||||
|
the job, with `SHARED_IO_BASE_DIR` under the mounted PVC. The successful run logs
|
||||||
|
confirm it:
|
||||||
|
|
||||||
|
> Handled output "result" using IO manager "io_manager" —
|
||||||
|
> `/dagster/shared/distributed-execution/storage/1d8cb167-…/generate_work_units/result/unit_0`
|
||||||
|
|
||||||
|
The platform run exposed the false-positive `DAGSTER_POSTGRES_*` warning
|
||||||
|
described under T1 above. The reference now checks the chart's actual
|
||||||
|
`DAGSTER_PG_PASSWORD` injection instead.
|
||||||
|
|
||||||
|
> Note: `report_execution_target` reported `namespace: <not-in-kubernetes>` on a
|
||||||
|
> step pod that plainly was in Kubernetes. The check reads the service account
|
||||||
|
> namespace file, which is absent when the token is not automounted. It is a
|
||||||
|
> property of the probe, not of the run.
|
||||||
|
|
||||||
|
**C6 passes, contrary to what `job_namespace` alone suggests.** The launcher's
|
||||||
|
`job_namespace: dagster` is only a default. Each code location ships a
|
||||||
|
`DAGSTER_CONTAINER_CONTEXT` environment variable — generated by the chart — whose
|
||||||
|
`k8s.namespace` is `dataprovider01`, and the code location's context is merged
|
||||||
|
*over* the launcher's, so it wins (`dagster_k8s/container_context.py`: `namespace
|
||||||
|
= other.namespace if other.namespace else self.namespace`). Run pods therefore
|
||||||
|
land in `dataprovider01`, where `dagster-instance`, `dagster-postgresql-secret`
|
||||||
|
and `dagster-shared-pvc` all exist.
|
||||||
|
|
||||||
|
Both deployed code locations carry it, so both would launch correctly:
|
||||||
|
|
||||||
|
| Code location | `DAGSTER_CONTAINER_CONTEXT` `k8s.namespace` |
|
||||||
|
|---|---|
|
||||||
|
| `template-code-location` | `dataprovider01` |
|
||||||
|
| `semaphore-ui` | `dataprovider01` |
|
||||||
|
|
||||||
|
The successful run confirms that the code-location container context places run
|
||||||
|
and step pods in `dataprovider01` with the required namespace-local dependencies.
|
||||||
|
|
||||||
|
The residual risk is narrower than a broken namespace, but real: a code location
|
||||||
|
that reaches the launcher *without* a container context namespace inherits
|
||||||
|
`dagster` and would fail on three missing objects. The chart always sets it, so
|
||||||
|
this bites only hand-rolled pods — the reason the C6 row asks you to check the
|
||||||
|
launcher's namespace-local dependencies rather than just the namespace.
|
||||||
|
|
||||||
|
> An earlier revision of this section claimed C6 failed and that this explained
|
||||||
|
> the absence of runs. That was wrong: it read `job_namespace` without accounting
|
||||||
|
> for the container-context override.
|
||||||
|
|
||||||
## 3. Loosely coupled checks
|
## 3. Loosely coupled checks
|
||||||
|
|
||||||
| # | Check | How to verify | Expected evidence |
|
| # | Check | How to verify | Expected evidence |
|
||||||
@@ -46,7 +197,7 @@ location image.
|
|||||||
| L1 | Payload contract is intact | `uv run pytest tests/test_loosely_coupled.py` | `test_payload_does_not_import_dagster` passes — the payload imports `dagster_pipes` only |
|
| L1 | Payload contract is intact | `uv run pytest tests/test_loosely_coupled.py` | `test_payload_does_not_import_dagster` passes — the payload imports `dagster_pipes` only |
|
||||||
| L2 | Pipes round trip works | Launch `loosely_coupled_subprocess_job` | Run reaches `SUCCESS`; run logs contain the payload's `External payload started on …` line, proving `pipes.log` crossed the channel |
|
| L2 | Pipes round trip works | Launch `loosely_coupled_subprocess_job` | Run reaches `SUCCESS`; run logs contain the payload's `External payload started on …` line, proving `pipes.log` crossed the channel |
|
||||||
| L3 | Silence is treated as failure | Same test module | `test_silent_message_path_is_treated_as_failure` passes — an empty message list raises rather than yielding an empty result |
|
| L3 | Silence is treated as failure | Same test module | `test_silent_message_path_is_treated_as_failure` passes — an empty message list raises rather than yielding an empty result |
|
||||||
| L4 | Payload image is pullable by the target cluster | `kubectl -n <payload-ns> run pull-probe --image=<payload-image> --restart=Never --command -- true` | Pod reaches `Completed`; no `ImagePullBackOff` |
|
| L4 | Payload image is pullable by the target cluster | `kubectl -n <payload-ns> run pull-probe --image=<payload-image> --restart=Never --command -- true` | Pod reaches `Completed`; no `ImagePullBackOff`. Both Gitea images pull anonymously — a bare registry `GET` returns 401, but that is the start of the Docker token handshake, not a refusal |
|
||||||
| L5 | Dispatcher can create Jobs in the payload namespace | `kubectl -n <payload-ns> auth can-i create jobs --as=system:serviceaccount:dagster:dagster-dev` | Returns `yes` |
|
| L5 | Dispatcher can create Jobs in the payload namespace | `kubectl -n <payload-ns> auth can-i create jobs --as=system:serviceaccount:dagster:dagster-dev` | Returns `yes` |
|
||||||
| L6 | Dispatcher can read pod logs — **the message channel** | `kubectl -n <payload-ns> auth can-i get pods/log --as=system:serviceaccount:dagster:dagster-dev` | Returns `yes`. A `no` here breaks reporting *without* failing the workload |
|
| L6 | Dispatcher can read pod logs — **the message channel** | `kubectl -n <payload-ns> auth can-i get pods/log --as=system:serviceaccount:dagster:dagster-dev` | Returns `yes`. A `no` here breaks reporting *without* failing the workload |
|
||||||
| L7 | Payload Job is actually created | Launch `loosely_coupled_k8s_job`, then `kubectl -n <payload-ns> get jobs -l app.kubernetes.io/name=distributed-execution-payload` | One Job per dispatch, labelled `dagster/execution-target=loosely-coupled` |
|
| L7 | Payload Job is actually created | Launch `loosely_coupled_k8s_job`, then `kubectl -n <payload-ns> get jobs -l app.kubernetes.io/name=distributed-execution-payload` | One Job per dispatch, labelled `dagster/execution-target=loosely-coupled` |
|
||||||
@@ -58,6 +209,26 @@ location image.
|
|||||||
Checks L4–L9 require a cluster. L1–L3, L10 and L11 run on a laptop and should
|
Checks L4–L9 require a cluster. L1–L3, L10 and L11 run on a laptop and should
|
||||||
gate every change to the payload or the dispatching op.
|
gate every change to the payload or the dispatching op.
|
||||||
|
|
||||||
|
`yaml/loosely-coupled/probe-pipes-k8s.yaml` clears L4–L9 in a single run from a
|
||||||
|
throwaway namespace, without deploying a code location or a Dagster control
|
||||||
|
plane. Prefer it over assembling the cluster checks by hand: the RBAC it grants
|
||||||
|
is exactly the set L5 and L6 ask about, so a failure localises immediately.
|
||||||
|
|
||||||
|
**L4–L10 were cleared on sandbox-cat-dat on 2026-08-31** using the sandbox
|
||||||
|
variant `yaml/sandbox/probe-pipes-k8s-sandbox.yaml`. Run
|
||||||
|
`cff9b348-bfc3-4ac1-ab51-a94892b8e3a0` reached `RUN_SUCCESS` in `dataprovider01`:
|
||||||
|
four payload Jobs, four distinct payload pod hostnames in `contributing_hosts`,
|
||||||
|
and the payload's `External payload started on …` lines in the dispatcher's log,
|
||||||
|
which is the pod log stream doing its job as the message channel. No credentials
|
||||||
|
were needed anywhere.
|
||||||
|
|
||||||
|
One trap the run exposed. The platform's `dagster-svc-account` sets
|
||||||
|
`automountServiceAccountToken: false`, and the Dagster chart overrides it to
|
||||||
|
`true` on every pod it manages. A hand-written pod that does not is a plausible
|
||||||
|
future failure: the pipes client selects in-cluster authentication correctly and
|
||||||
|
then fails on `Service token file does not exist`, which points at Kubernetes
|
||||||
|
rather than at the omission.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 4. Common misconfiguration symptoms
|
## 4. Common misconfiguration symptoms
|
||||||
@@ -79,6 +250,7 @@ gate every change to the payload or the dispatching op.
|
|||||||
| `env_vars_missing` is non-empty in `report_execution_target` metadata | Env vars are set on the code location deployment but not on the run pod | Add them under `runLauncher.config.k8sRunLauncher.runK8sConfig.containerConfig.env` — code location env is **not** inherited by run pods |
|
| `env_vars_missing` is non-empty in `report_execution_target` metadata | Env vars are set on the code location deployment but not on the run pod | Add them under `runLauncher.config.k8sRunLauncher.runK8sConfig.containerConfig.env` — code location env is **not** inherited by run pods |
|
||||||
| A literal `vault:...` string appears as a value at runtime | Vault mutating webhook did not process the pod | Verify the `vault.security.banzaicloud.io/*` annotations are on the **run pod** template, not only the code location pod |
|
| A literal `vault:...` string appears as a value at runtime | Vault mutating webhook did not process the pod | Verify the `vault.security.banzaicloud.io/*` annotations are on the **run pod** template, not only the code location pod |
|
||||||
| Steps hang in `STARTING` with `k8s_job_executor` | Service account lacks Job create/watch permission | Apply `yaml/tightly-coupled/rbac-step-executor.yaml` and confirm with `kubectl auth can-i` |
|
| Steps hang in `STARTING` with `k8s_job_executor` | Service account lacks Job create/watch permission | Apply `yaml/tightly-coupled/rbac-step-executor.yaml` and confirm with `kubectl auth can-i` |
|
||||||
|
| `FileNotFoundError` loading a step input from `/tmp/dagster/storage/...` | Step pods each use their own container filesystem for I/O manager output | Mount an RWX volume into step pods via `step_k8s_config` **and** pin `fs_io_manager`'s `base_dir` under it. Setting `DAGSTER_HOME` in `step_k8s_config` does not work — the chart's `DAGSTER_HOME=/tmp/dagster` is injected first and wins |
|
||||||
| `contributing_hosts` shows one host when `k8s_job_executor` is configured | Run tags or Launchpad config overrode the executor, or the image predates the change | Confirm the code location reloaded after the image bump; check the run's *Config* tab for an `execution:` override |
|
| `contributing_hosts` shows one host when `k8s_job_executor` is configured | Run tags or Launchpad config overrode the executor, or the image predates the change | Confirm the code location reloaded after the image bump; check the run's *Config* tab for an `execution:` override |
|
||||||
| Step pods `OOMKilled` under fan-out | Per-step memory limit applied per pod, aggregate exceeded quota | Raise `step_k8s_config` limits or lower step concurrency; the two multiply |
|
| Step pods `OOMKilled` under fan-out | Per-step memory limit applied per pod, aggregate exceeded quota | Raise `step_k8s_config` limits or lower step concurrency; the two multiply |
|
||||||
| Postgres refuses connections once fan-out grows | Each step pod is an independent DB client | Reduce step concurrency, raise the Postgres connection limit, or move the fan-out step to a loosely coupled target |
|
| Postgres refuses connections once fan-out grows | Each step pod is an independent DB client | Reduce step concurrency, raise the Postgres connection limit, or move the fan-out step to a loosely coupled target |
|
||||||
@@ -96,9 +268,17 @@ gate every change to the payload or the dispatching op.
|
|||||||
| Payload receives no `units` | `extras` key mismatch between dispatcher and `pipes.get_extra()` | Both sides must use the same key; a typo yields a `KeyError` inside the payload |
|
| Payload receives no `units` | `extras` key mismatch between dispatcher and `pipes.get_extra()` | Both sides must use the same key; a typo yields a `KeyError` inside the payload |
|
||||||
| Run cancelled in the UI, payload pod keeps running | Cancellation is not propagated to dispatched workloads automatically | `delete_pod_on_completion` handles the normal path; for cancellation, verify orphaned Jobs and add a cleanup sensor |
|
| Run cancelled in the UI, payload pod keeps running | Cancellation is not propagated to dispatched workloads automatically | `delete_pod_on_completion` handles the normal path; for cancellation, verify orphaned Jobs and add a cleanup sensor |
|
||||||
|
|
||||||
> **NOT CLUSTER-VERIFIED.** Rows referencing Kubernetes behaviour follow from the
|
> **Partly observed.** The pipes rows were exercised on sandbox-cat-dat on
|
||||||
> implemented reference and the dagster-k8s API, but have not been observed on a
|
> 2026-08-31. The tightly coupled `k8s_job_executor` rows were closed on
|
||||||
> Simpl cluster. Confirm and amend after the first cluster run.
|
> 2026-09-01 by run `1d8cb167-9fb8-4a34-a036-789eac381e13`; the remaining rows in
|
||||||
|
> the table above still follow from the dagster-k8s API rather than from
|
||||||
|
> observation.
|
||||||
|
>
|
||||||
|
> One symptom the cluster run added, absent from the table above: a service
|
||||||
|
> account with `automountServiceAccountToken: false` — which the platform's
|
||||||
|
> `dagster-svc-account` uses — makes the pipes client fail with
|
||||||
|
> `ConfigException: Service token file does not exist`. It reads as a Kubernetes
|
||||||
|
> fault; the fix is `automountServiceAccountToken: true` on the pod.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
PROJECT_VERSION_NUMBER="0.1.0"
|
PROJECT_VERSION_NUMBER="0.0.1"
|
||||||
|
|||||||
@@ -3,11 +3,16 @@ name = "distributed_execution"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
description = "Reference implementations and user guide for Dagster distributed execution targets and integration patterns"
|
description = "Reference implementations and user guide for Dagster distributed execution targets and integration patterns"
|
||||||
requires-python = ">=3.12"
|
requires-python = ">=3.12"
|
||||||
|
# Pinned to the exact control plane version, not just the 1.12 line. A code
|
||||||
|
# location is a gRPC server the webserver and daemon call into, and step pods
|
||||||
|
# share a metadata database schema with them. Patch releases can carry schema
|
||||||
|
# migrations, so "close enough" is not a safe position against a shared database.
|
||||||
|
# Revisit when the platform upgrades; the libraries track dagster as 0.28.x.
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dagster",
|
"dagster==1.12.8",
|
||||||
"dagster-k8s>=0.27.16",
|
"dagster-k8s==0.28.8",
|
||||||
"dagster-postgres>=0.27.16",
|
"dagster-postgres==0.28.8",
|
||||||
"dagster-webserver>=1.11.16",
|
"dagster-webserver==1.12.8",
|
||||||
"pip>=26.1.2",
|
"pip>=26.1.2",
|
||||||
"pydantic>=2.0",
|
"pydantic>=2.0",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
dagster
|
dagster==1.12.8
|
||||||
dagster-k8s>=0.27.16
|
dagster-k8s==0.28.8
|
||||||
dagster-postgres>=0.27.16
|
dagster-postgres==0.28.8
|
||||||
dagster-webserver>=1.11.16
|
dagster-webserver==1.12.8
|
||||||
pip>=26.1.2
|
pip>=26.1.2
|
||||||
pydantic>=2.0
|
pydantic>=2.0
|
||||||
|
|||||||
@@ -38,7 +38,8 @@ PAYLOAD_SCRIPT = os.environ.get("PIPES_PAYLOAD_SCRIPT", str(_REPO_ROOT / "payloa
|
|||||||
|
|
||||||
PAYLOAD_IMAGE = os.environ.get(
|
PAYLOAD_IMAGE = os.environ.get(
|
||||||
"PIPES_PAYLOAD_IMAGE",
|
"PIPES_PAYLOAD_IMAGE",
|
||||||
"code.europa.eu:4567/simpl/simpl-open/data/supporting-data-services/distributed-execution/payload:0.1.0",
|
"code.europa.eu:4567/simpl/simpl-open/data/supporting-data-services"
|
||||||
|
"/distributed-execution/distributed-execution/payload:0.0.1",
|
||||||
)
|
)
|
||||||
PAYLOAD_NAMESPACE = os.environ.get("PIPES_PAYLOAD_NAMESPACE", "dagster")
|
PAYLOAD_NAMESPACE = os.environ.get("PIPES_PAYLOAD_NAMESPACE", "dagster")
|
||||||
|
|
||||||
|
|||||||
@@ -12,9 +12,7 @@ from urllib.parse import urlparse
|
|||||||
|
|
||||||
# Runtime dependencies a tightly coupled execution pod must be able to resolve.
|
# Runtime dependencies a tightly coupled execution pod must be able to resolve.
|
||||||
TIGHTLY_COUPLED_ENV_VARS = (
|
TIGHTLY_COUPLED_ENV_VARS = (
|
||||||
"DAGSTER_POSTGRES_HOST",
|
"DAGSTER_PG_PASSWORD",
|
||||||
"DAGSTER_POSTGRES_USER",
|
|
||||||
"DAGSTER_POSTGRES_DB",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ is the instance-level run launcher (see ``yaml/tightly-coupled/``).
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from dagster import graph, in_process_executor, multiprocess_executor
|
from dagster import fs_io_manager, graph, in_process_executor, multiprocess_executor
|
||||||
from dagster_k8s import k8s_job_executor
|
from dagster_k8s import k8s_job_executor
|
||||||
|
|
||||||
from distributed_execution.ops import (
|
from distributed_execution.ops import (
|
||||||
@@ -28,6 +28,11 @@ COMMON_TAGS = {
|
|||||||
"business_operation": "DISTRIBUTED_EXECUTION_REFERENCE",
|
"business_operation": "DISTRIBUTED_EXECUTION_REFERENCE",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# RWX PVC mounted into the run worker and every step pod. Set as the I/O manager
|
||||||
|
# base_dir rather than via DAGSTER_HOME: the Dagster chart already injects
|
||||||
|
# DAGSTER_HOME=/tmp/dagster and the earlier duplicate wins in the step pod.
|
||||||
|
SHARED_IO_BASE_DIR = "/dagster/shared/distributed-execution/storage"
|
||||||
|
|
||||||
# Per-step pod shape. Only honoured by k8s_job_executor.
|
# Per-step pod shape. Only honoured by k8s_job_executor.
|
||||||
STEP_K8S_CONFIG = {
|
STEP_K8S_CONFIG = {
|
||||||
"container_config": {
|
"container_config": {
|
||||||
@@ -35,9 +40,21 @@ STEP_K8S_CONFIG = {
|
|||||||
"requests": {"cpu": "100m", "memory": "128Mi"},
|
"requests": {"cpu": "100m", "memory": "128Mi"},
|
||||||
"limits": {"cpu": "500m", "memory": "512Mi"},
|
"limits": {"cpu": "500m", "memory": "512Mi"},
|
||||||
},
|
},
|
||||||
|
"volume_mounts": [
|
||||||
|
{
|
||||||
|
"name": "dagster-shared-storage",
|
||||||
|
"mount_path": "/dagster/shared",
|
||||||
|
}
|
||||||
|
],
|
||||||
},
|
},
|
||||||
"pod_spec_config": {
|
"pod_spec_config": {
|
||||||
"restart_policy": "Never",
|
"restart_policy": "Never",
|
||||||
|
"volumes": [
|
||||||
|
{
|
||||||
|
"name": "dagster-shared-storage",
|
||||||
|
"persistent_volume_claim": {"claim_name": "dagster-shared-pvc"},
|
||||||
|
}
|
||||||
|
],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,12 +98,21 @@ tightly_coupled_k8s_job = distributed_execution_reference.to_job(
|
|||||||
"Tightly coupled, one Kubernetes Job per step. Each step pod must reach the metadata "
|
"Tightly coupled, one Kubernetes Job per step. Each step pod must reach the metadata "
|
||||||
"database, object storage and Vault. Requires a cluster - not runnable locally."
|
"database, object storage and Vault. Requires a cluster - not runnable locally."
|
||||||
),
|
),
|
||||||
executor_def=k8s_job_executor.configured(
|
# Defaults go through `config` rather than `executor_def=...configured(...)`.
|
||||||
{
|
# `.configured()` collapses the executor's config schema to Any, so a run
|
||||||
|
# config `execution:` block is accepted and then silently discarded - which
|
||||||
|
# also makes job_image and job_namespace impossible to supply at launch time.
|
||||||
|
executor_def=k8s_job_executor,
|
||||||
|
# Steps run in separate pods, so step outputs have to land on shared storage.
|
||||||
|
resource_defs={"io_manager": fs_io_manager.configured({"base_dir": SHARED_IO_BASE_DIR})},
|
||||||
|
config={
|
||||||
|
"execution": {
|
||||||
|
"config": {
|
||||||
"image_pull_policy": "IfNotPresent",
|
"image_pull_policy": "IfNotPresent",
|
||||||
"step_k8s_config": STEP_K8S_CONFIG,
|
"step_k8s_config": STEP_K8S_CONFIG,
|
||||||
}
|
}
|
||||||
),
|
}
|
||||||
|
},
|
||||||
tags={**COMMON_TAGS, "executor": "k8s_job"},
|
tags={**COMMON_TAGS, "executor": "k8s_job"},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -65,9 +65,7 @@ def test_each_unit_is_dispatched_to_its_own_external_worker():
|
|||||||
|
|
||||||
|
|
||||||
def test_payload_reports_no_orchestration_credentials(monkeypatch):
|
def test_payload_reports_no_orchestration_credentials(monkeypatch):
|
||||||
monkeypatch.delenv("DAGSTER_POSTGRES_HOST", raising=False)
|
monkeypatch.delenv("DAGSTER_PG_PASSWORD", raising=False)
|
||||||
monkeypatch.delenv("DAGSTER_POSTGRES_USER", raising=False)
|
|
||||||
monkeypatch.delenv("DAGSTER_POSTGRES_DB", raising=False)
|
|
||||||
|
|
||||||
result = loosely_coupled_subprocess_job.execute_in_process()
|
result = loosely_coupled_subprocess_job.execute_in_process()
|
||||||
mapped = result.output_for_node("dispatch_external_work_subprocess")
|
mapped = result.output_for_node("dispatch_external_work_subprocess")
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import pytest
|
|||||||
from distributed_execution.preflight import check_env_vars, describe_pod_identity
|
from distributed_execution.preflight import check_env_vars, describe_pod_identity
|
||||||
from distributed_execution.repository import defs
|
from distributed_execution.repository import defs
|
||||||
from distributed_execution.tightly_coupled.jobs import (
|
from distributed_execution.tightly_coupled.jobs import (
|
||||||
|
SHARED_IO_BASE_DIR,
|
||||||
|
STEP_K8S_CONFIG,
|
||||||
tightly_coupled_in_process_job,
|
tightly_coupled_in_process_job,
|
||||||
tightly_coupled_k8s_job,
|
tightly_coupled_k8s_job,
|
||||||
tightly_coupled_local_job,
|
tightly_coupled_local_job,
|
||||||
@@ -35,6 +37,24 @@ def test_each_job_declares_its_execution_target(job, expected_executor):
|
|||||||
assert job.tags["executor"] == expected_executor
|
assert job.tags["executor"] == expected_executor
|
||||||
|
|
||||||
|
|
||||||
|
def test_k8s_step_pods_mount_shared_dagster_storage():
|
||||||
|
container_config = STEP_K8S_CONFIG["container_config"]
|
||||||
|
pod_spec_config = STEP_K8S_CONFIG["pod_spec_config"]
|
||||||
|
|
||||||
|
assert {"name": "dagster-shared-storage", "mount_path": "/dagster/shared"} in container_config["volume_mounts"]
|
||||||
|
assert {
|
||||||
|
"name": "dagster-shared-storage",
|
||||||
|
"persistent_volume_claim": {"claim_name": "dagster-shared-pvc"},
|
||||||
|
} in pod_spec_config["volumes"]
|
||||||
|
assert SHARED_IO_BASE_DIR.startswith("/dagster/shared/")
|
||||||
|
|
||||||
|
|
||||||
|
def test_k8s_job_pins_io_manager_to_shared_storage():
|
||||||
|
io_manager = tightly_coupled_k8s_job.resource_defs["io_manager"]
|
||||||
|
resolved = io_manager.apply_config_mapping({}).value
|
||||||
|
assert resolved["config"]["base_dir"] == SHARED_IO_BASE_DIR
|
||||||
|
|
||||||
|
|
||||||
def test_in_process_job_runs_end_to_end():
|
def test_in_process_job_runs_end_to_end():
|
||||||
result = tightly_coupled_in_process_job.execute_in_process()
|
result = tightly_coupled_in_process_job.execute_in_process()
|
||||||
|
|
||||||
@@ -61,6 +81,16 @@ def test_env_var_check_reports_missing_names():
|
|||||||
assert result["missing"] == ["DEFINITELY_NOT_SET_12345"]
|
assert result["missing"] == ["DEFINITELY_NOT_SET_12345"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_env_var_check_reports_present_names(monkeypatch):
|
||||||
|
monkeypatch.setenv("DAGSTER_PG_PASSWORD", "not-exposed-in-evidence")
|
||||||
|
|
||||||
|
result = check_env_vars(("DAGSTER_PG_PASSWORD",))
|
||||||
|
|
||||||
|
assert result["passed"] is True
|
||||||
|
assert result["present"] == ["DAGSTER_PG_PASSWORD"]
|
||||||
|
assert "not-exposed-in-evidence" not in repr(result)
|
||||||
|
|
||||||
|
|
||||||
def test_pod_identity_falls_back_outside_kubernetes(monkeypatch):
|
def test_pod_identity_falls_back_outside_kubernetes(monkeypatch):
|
||||||
monkeypatch.delenv("DAGSTER_K8S_PIPELINE_RUN_NAMESPACE", raising=False)
|
monkeypatch.delenv("DAGSTER_K8S_PIPELINE_RUN_NAMESPACE", raising=False)
|
||||||
|
|
||||||
|
|||||||
294
uv.lock
generated
294
uv.lock
generated
@@ -7,128 +7,6 @@ resolution-markers = [
|
|||||||
"python_full_version < '3.13'",
|
"python_full_version < '3.13'",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "aiohappyeyeballs"
|
|
||||||
version = "2.7.1"
|
|
||||||
source = { registry = "https://pypi.org/simple" }
|
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/ce/f4/eec0465c2f67b2664688d0240b3212d5196fd89e741df67ddb81f8d35658/aiohappyeyeballs-2.7.1.tar.gz", hash = "sha256:065665c041c42a5938ed220bdcd7230f22527fbec085e1853d2402c8a3615d9d", size = 24757, upload-time = "2026-07-01T17:11:55.501Z" }
|
|
||||||
wheels = [
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl", hash = "sha256:9243213661e29250eb41368e5daa826fc017156c3b8a11440826b2e3ed376472", size = 15038, upload-time = "2026-07-01T17:11:54.055Z" },
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "aiohttp"
|
|
||||||
version = "3.14.3"
|
|
||||||
source = { registry = "https://pypi.org/simple" }
|
|
||||||
dependencies = [
|
|
||||||
{ name = "aiohappyeyeballs" },
|
|
||||||
{ name = "aiosignal" },
|
|
||||||
{ name = "attrs" },
|
|
||||||
{ name = "frozenlist" },
|
|
||||||
{ name = "multidict" },
|
|
||||||
{ name = "propcache" },
|
|
||||||
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
|
||||||
{ name = "yarl" },
|
|
||||||
]
|
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/58/d9/22ce5786ac0c1653ae8b6c23bded02c1686d11f0dbb45b31ce128e0df985/aiohttp-3.14.3.tar.gz", hash = "sha256:9491196535a88924a60afd5b5f434b5b203b6cc616250878dbdb223a8f7844bc", size = 7971213, upload-time = "2026-07-23T01:57:27.037Z" }
|
|
||||||
wheels = [
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/18/d4/eb96299230e20acf2efae207cb8d69051f1f68e357e5ea5e479bf6fb097a/aiohttp-3.14.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:39aded8c7f3b935b54aab1d8d73c70ec0ee2d3ec3b943e0e86611bc150ba47f5", size = 754690, upload-time = "2026-07-23T01:53:47.332Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/88/11/e7a70a209eb9a067c0d3212b518a0134e3484f5178c7533878b6b514d469/aiohttp-3.14.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5bcb6ff3fdab1258a192679ff1a05d44f59626430aa05cd1a9d2447423599228", size = 509484, upload-time = "2026-07-23T01:53:51.159Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/30/07/4bbc222cc8dbe31d4c3e8a5baad2286e4d42026ac0c570027b89afce6344/aiohttp-3.14.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:617105e2c3018ee38d0c8ce5ee3c84f621a6d8b9f723202aacaff28449ca91ee", size = 511949, upload-time = "2026-07-23T01:53:55.083Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/54/b9/42e74c46b7b7c794b995bbc1f573fb48950c38b19d8600c62a6804ee2d67/aiohttp-3.14.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f631fe87a6f30df5fbe6d79640b25e4cffb38c31c7fb6f10871517b84b0f8c1a", size = 1765282, upload-time = "2026-07-23T01:53:59.662Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/6b/ed/62bc4d74363ad346d518e0720363a949f63e2e23439a79eb5813d4d29bb3/aiohttp-3.14.3-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a94dbaae5ae27bd849c93570669bff91e0510f33a80805738e3de72a7be0447b", size = 1741511, upload-time = "2026-07-23T01:54:04.063Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/d0/9f/181e8a8bc79e47d13c7fc4540bd7a3b729d9505609c61f392a8dd2fbfe55/aiohttp-3.14.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8f2f1c4c032c7cedd7d8da6f54c97b70266c6570c3108d3fdffee7188bb70529", size = 1810680, upload-time = "2026-07-23T01:54:09.882Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/5c/9a/dec94d6ad694552fe3424e3f1928d7a606a5d9d9433a04e7ecdd9d38ae7f/aiohttp-3.14.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ea05e1f97ceea523942d9b2a7d7c0359d781d683d6b043f5943a602b14da4787", size = 1905646, upload-time = "2026-07-23T01:54:13.475Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/52/b7/7cd31f29d6055bd711ae6e669367fba6f5ae9de463910a793e30556a8db7/aiohttp-3.14.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:543906c127fb1d929b95076db19b83fa2d46751006ff1e23b093aa5ac4d8db42", size = 1792122, upload-time = "2026-07-23T01:54:15.752Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/66/73/10b1ef93afa61f4963c746257b70ced619cf31a4798671de5fdb2608501d/aiohttp-3.14.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0a5ff2dfbb9ce645fa5b8ef3e02c6c0b9cc3f6030ff863d0c51fffc50cb5541b", size = 1591127, upload-time = "2026-07-23T01:54:19.489Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/49/ed/3b203fa6de1b338c14acdc06bf6ca9b043b7944f005966958c2ced932cde/aiohttp-3.14.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:041badb8f84396357c4d3ad26de6afd7a32b112f43d3c63045c0c8278cfd2043", size = 1725210, upload-time = "2026-07-23T01:54:24.129Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/28/b7/1c2aab8c706436dcc28598452488ac9cd7c409da815237c28c27d58993e6/aiohttp-3.14.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:530125ee1163c4219af35dc3aa1206e541e7b31b6efc1a3f93b70a136f65d427", size = 1764848, upload-time = "2026-07-23T01:54:27.973Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/54/50/94c28f08b131c4bf10984ea2c7a536c9920608bb2d6e7f95642c30cc87b7/aiohttp-3.14.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c8653fd547c93a61aadc612007790f5555cdd18946fa48cf45e26d8ea4ea473d", size = 1777102, upload-time = "2026-07-23T01:54:31.775Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/13/d4/e7d09ba7d345fb2d74440fd2fa033c5e079fac05552927705986f41a364f/aiohttp-3.14.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:89176250f686cb9853c0fb7ead90e639e915b84a6f43eedc2a4e7ec21f1037f0", size = 1580205, upload-time = "2026-07-23T01:54:34.518Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/a3/84/072a91d68e1e1eb587985b54baab94221277f877e8ef274fc213a0ceae28/aiohttp-3.14.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3a26434dafe408229ff3403458ca58de24fb51936504decac49ce6755f77e59d", size = 1797219, upload-time = "2026-07-23T01:54:36.995Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/e0/eb/aad34e897e668424d6e995da5dff8a4a09af93363d3392488772957a63aa/aiohttp-3.14.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d1558173930a5a8d3069cee5c92fc91c87c4dbcb099debbb3622053717145a19", size = 1768629, upload-time = "2026-07-23T01:54:40.103Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/b6/2b/6bb88ddba0fecd9122aa3ebcad25996cf6c083a4a7040dbb3a4f97972af6/aiohttp-3.14.3-cp312-cp312-win32.whl", hash = "sha256:16100ad3ab8d649fdfbee87602d9d2dcdca9df0b9eda8a1b5fdc0d41f96da559", size = 451481, upload-time = "2026-07-23T01:54:42.547Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/76/9b/f2f8f108da17ecef2cc3efc424e8b7ad3782b1a8360f7b8eae8ced84f6ea/aiohttp-3.14.3-cp312-cp312-win_amd64.whl", hash = "sha256:33a2d7c28d33797a2e99923dffa63f83d908a19b6bf26cfe80fa790aa5e1a75a", size = 476845, upload-time = "2026-07-23T01:54:44.853Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/3e/44/28dac80a8941b604f4da10ce21097614ca1bf905ce93dca28d8d7de9c1e7/aiohttp-3.14.3-cp312-cp312-win_arm64.whl", hash = "sha256:362a3fd481769cac1a824514bcd86fda51c65e8fe6e051099e008fddde6db17c", size = 448050, upload-time = "2026-07-23T01:54:47.087Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/57/be/5afd201cc0ab139029aadb75392efe85a293403d9dd3a3226161c21ce00c/aiohttp-3.14.3-cp313-cp313-android_21_arm64_v8a.whl", hash = "sha256:2e9878ae68e4a5f1c0abe4dd497dbc3d51946f5837b56759e2a02e78fa90ef86", size = 506269, upload-time = "2026-07-23T01:54:49.075Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/22/09/dec8189d62b45ade009f6792a2264b942a90cb88aeaf181239933cd72c3c/aiohttp-3.14.3-cp313-cp313-android_21_x86_64.whl", hash = "sha256:f3d2669fe7dec7fc359ecdb5984b29b50d85d5d00f8c1cb61de4f4a24ee42627", size = 515166, upload-time = "2026-07-23T01:54:51.894Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/28/24/2854869d29ed8a8b19d74f9ec6629515f7e04d02dd329d9d179201e58e47/aiohttp-3.14.3-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:cc7cb243a68167172f48c1fd43cee91ec4b1d40cefd190edd43369d1a6bc9c82", size = 486263, upload-time = "2026-07-23T01:54:54.223Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/d4/dd/57187c8be2a35aea65eaee3bd2c3dcbbcf0204f5106c89637e3610380cd1/aiohttp-3.14.3-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:78253b573e6ffab5028924fc98bc281aae05445969982a10864bc360dea2016c", size = 492299, upload-time = "2026-07-23T01:54:56.236Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/b9/11/06ae6ed8f0d414edf4068861e233d8fe23ee699bfd4b3ceb8663db948a62/aiohttp-3.14.3-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:7041d52c3a7fa20c9e8c182b534704abb19502c8bdcbde7ab23bfda6f642394f", size = 502235, upload-time = "2026-07-23T01:54:58.377Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/7e/a3/559639c34a345d2cf7c52dff6838119f2eaf29eb508227b5b83f573af813/aiohttp-3.14.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ac74facc01463f138b0da5580329cfcc82818dea5656e83ddcd11268fc12ff80", size = 750883, upload-time = "2026-07-23T01:55:00.65Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/91/cd/41e131f13afd1e7b0172a9d9eda085ef90eb8439f41f0d279db81ed3ae60/aiohttp-3.14.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d6218d92e450824e9b4881f44e8c09f1853b490f9a64130801024a4793b1b3b0", size = 508473, upload-time = "2026-07-23T01:55:02.945Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/bc/6b/e7f13410d391c6e55b4c007a8de024355389d7d459e3d64c42b2d33617e5/aiohttp-3.14.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:11fb37ef075669eee52ab1928fbf6e1741fada40409fa309ebde9607a962aebf", size = 509190, upload-time = "2026-07-23T01:55:05.173Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/97/21/6464573e53d69672cc1eada3e5c5cb2d2efa82701e8305a0f2047a576967/aiohttp-3.14.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:55bdcc472aafe2de4a253045cc128007a64f1e0264fb675791e132ea5edaa3bd", size = 1761478, upload-time = "2026-07-23T01:55:07.383Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/1a/81/d217043a4c17fbce360905e3b2bdd20139ebc9a2de836d035d179c4da006/aiohttp-3.14.3-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c39846c3aad97a8530c89d7a3869a8f8e9e3762c6ac0504481e5c80948f7e807", size = 1735092, upload-time = "2026-07-23T01:55:09.803Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/a1/66/e13a02d0eeb1a9a502402a977abb4e4abff9fe4051c26f80558c57a7c975/aiohttp-3.14.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5895ef58c4620afe02fa16044f023dc4dafec08158f9d08874a46a7dbc0341b8", size = 1800546, upload-time = "2026-07-23T01:55:12.012Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/26/5e/57d42fca1d18cb5acc1cad945d017fabc5d6ae71d8a08ad66be8dc3ee544/aiohttp-3.14.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fa9467a8113aa69d3d7c55a70ef0b7c636010a40993f3df9d9d0d73b3eb7ef24", size = 1895250, upload-time = "2026-07-23T01:55:14.357Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/ca/1c/7da8d08e74d56f00070822f9638ff3f1c563f8ad87d1efa996c87bfc8644/aiohttp-3.14.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d7d2deec16eeedf55f2c7cf75b521ea3856a5177e123844f8fd0f114ce252cb5", size = 1789289, upload-time = "2026-07-23T01:55:16.668Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/cd/0f/cf16bcf56896981c1a0319f5d5db9337994b5165730c48a8fa07e9b34be6/aiohttp-3.14.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:dd54d0e8717de95939766febac482ac0474d8ac3b048115f9f2b1d23a16e7db4", size = 1586706, upload-time = "2026-07-23T01:55:18.913Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/fe/6f/76eac12a7f2480e1e304f842efdb07db33256b0d9165b866b6ef0806c202/aiohttp-3.14.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:df82f3787c940c94986b34222d59c9e38843fba85139f36e85255a82ad5355a9", size = 1724652, upload-time = "2026-07-23T01:55:21.296Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/39/b6/19c8c592baeeb94b75f966547d40c02ac7590902306ec5863d5c027cf506/aiohttp-3.14.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:42a67efc36300d052fb4508a53e8b6901b9284b599ae63945c377569c5fcc1e1", size = 1756239, upload-time = "2026-07-23T01:55:23.705Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/dc/c9/4e9383150296f97f873b680c4de8fb2cd88608fb9f48c79edcb111611abc/aiohttp-3.14.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7a75aa63cbf9b21cfaf60dc2657e19df2c2867d91707d653fee171ffeedd1371", size = 1769161, upload-time = "2026-07-23T01:55:26.082Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/aa/1e/147bdc6cc5de5f3ab011be8bf5d6e786633249f22c20bae06f85e45f5387/aiohttp-3.14.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:e92eb8acc45eb6a9f4935071a77edf5b85cc6f8dfad5cd99e97653c26593cdde", size = 1578759, upload-time = "2026-07-23T01:55:28.846Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/fd/31/78388a9d6040ece2e11df62ea229a822cf5e52d238374b220ae9975b2623/aiohttp-3.14.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b014a6ed7cf912e787149fdc529166d3ceabac23f26efeea3158c9aba2354e7e", size = 1792025, upload-time = "2026-07-23T01:55:31.457Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/03/51/a3d29fdf2c25d796746af8ad6fe56a45d6256c38b0a8a2ed752e1160b3a2/aiohttp-3.14.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:3d4f72af88ac2474bb5bca640030320e3d38a0163a1d7533500e87be458eef71", size = 1768477, upload-time = "2026-07-23T01:55:33.87Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/29/a6/442e18b5afeade534d877a2dc3c3e392aff8d49787890b0cf84790410267/aiohttp-3.14.3-cp313-cp313-win32.whl", hash = "sha256:5f08ec777f35ee70720233b8b9811d3bb5d728137f30ac91b7457709c3261ac0", size = 451069, upload-time = "2026-07-23T01:55:36.121Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/9d/69/3d876ac02659f271cf7f6769f14a8e3de5b6e888ed8b5a7e998086a4cec8/aiohttp-3.14.3-cp313-cp313-win_amd64.whl", hash = "sha256:dff9461ec275f22135650d5ba4b4931a11f3958df7dfbb8db630000d4dee0883", size = 476518, upload-time = "2026-07-23T01:55:38.303Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/b2/0e/50d6e6471cd31edce8b282bdec59375a3a69124d8a989a0b1313355cae52/aiohttp-3.14.3-cp313-cp313-win_arm64.whl", hash = "sha256:ddcac3c6b382e81f1dd0499199d4136b877beb4cb5ef770bbbfba56c4b8f55d2", size = 447676, upload-time = "2026-07-23T01:55:40.451Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/c8/20/887fdcf832326571b370ffc347b3e70abe101096f3720126aac161b1d872/aiohttp-3.14.3-cp314-cp314-android_24_arm64_v8a.whl", hash = "sha256:49f7325beb0f85ef4aef5f48f490269575f83e6e2acad00a1d80b807eb027062", size = 509067, upload-time = "2026-07-23T01:55:42.618Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/ad/a3/92cec936f78cc4bf0fa5554ebe593b73459d94e3c62303e1902a4cccb6f7/aiohttp-3.14.3-cp314-cp314-android_24_x86_64.whl", hash = "sha256:e3be98a7c30b8c25d573dafba7171d66dfb05ee6a9070fc46535464ff97700a6", size = 514774, upload-time = "2026-07-23T01:55:44.937Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/29/ba/2a0c38df3fc557620b6a5acd98364af050053b6285b4dc7ee74100c63c18/aiohttp-3.14.3-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:614c61d478b83953e261d02bb2df750f17227cd33ef8002945bf5aebbde21919", size = 488134, upload-time = "2026-07-23T01:55:47.135Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/48/d6/d51b7d4bf309af3693940d8ffd2b9ed0b682434ef85959b7c9c137f60cf8/aiohttp-3.14.3-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:1caa7b0d05f3e3a36f87788c59e970a7ee1cefcfcbb924a9f138c4a6551c9cb7", size = 494201, upload-time = "2026-07-23T01:55:49.451Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/3f/5a/8f624384e5f1efabb5229b94157eb966b021e97bdb188c62860c2ae243c2/aiohttp-3.14.3-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:dfa68deb2a443bdaa3ea5297b0699c1464f08aef3812b486d1348eee61b07dc0", size = 502766, upload-time = "2026-07-23T01:55:51.656Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/a6/26/4ff0164370deec18fb19254ee4ab10b7a73304ac0c860b13f5f84663759b/aiohttp-3.14.3-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:e72ee89e28d907a18f46959b4eb0bb06701cc7f8cf4366e00029e2ccfaaf5924", size = 756557, upload-time = "2026-07-23T01:55:53.964Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/97/a3/7056b86dc0d9ec709ea9777eae3b0161428f943372f8b98c01c11593b682/aiohttp-3.14.3-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:ad4c8b7488d745d2ca4838ebd8ae5ba9b56341d30b1da43640e4ce87f9f49646", size = 510168, upload-time = "2026-07-23T01:55:56.22Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/85/ed/0357a015892fd68058bf2d39d3fd1958e459b997a7db30aaa6aaa434ae96/aiohttp-3.14.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:db332af25642007330fca8be5c4d194caf2bea7a7fc84415aff3497af5dfee6b", size = 512957, upload-time = "2026-07-23T01:55:58.437Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/47/d1/8aba53f15ccb2238405f5e9d30e2a8ca44f93878c26e7165ade00d374b1c/aiohttp-3.14.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:25bd2708db6bdf6a6630dd37bdcdfcb47c4434d22ac69c64665b802910140b30", size = 1750149, upload-time = "2026-07-23T01:56:00.856Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/49/bd/40c3fee327529284375c6701cbb0fa4600cc2e8432af1378f897e2ef7d3a/aiohttp-3.14.3-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:cef89a58e628c4efcac3275c2d68083f82426dcdc89c1492a6f654f9f7ea6ab9", size = 1707685, upload-time = "2026-07-23T01:56:03.371Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/2a/a3/ca0cc6724cca8114b05694abd916060758c79894c3aa5b012cdadc1bc28e/aiohttp-3.14.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c23ec8ee9d5ab2f5421f9c7fffce208435607af27fd46d4a44e031954352838f", size = 1803911, upload-time = "2026-07-23T01:56:05.817Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/95/b5/85b099c299c3ffd38ad9b3e43694c8a346934e4a30c88c4fd5a841234f77/aiohttp-3.14.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e2667f0bbe7eb6c74eae5e9691441ad186e5845ca3cff63230fc09c4e7514f5d", size = 1876929, upload-time = "2026-07-23T01:56:08.413Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/d5/b7/1da684a04175473fa4cddbf9a2f572e79514c3fd27a74597f43057d4f3da/aiohttp-3.14.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18cb43369747b2ae007bd2655fb8e63a099c2ff1d207962943636dac989b3147", size = 1761112, upload-time = "2026-07-23T01:56:10.918Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/d1/16/bc4b55e3e5cb175fd69c53c90d60d2f47797cb343da5106e23863dc4dba4/aiohttp-3.14.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d77640cc618c1d99fc4f8589c0f24a730adfa54eb1e57ef7bf0c8dfb78da898c", size = 1583500, upload-time = "2026-07-23T01:56:13.613Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/2a/e8/13a9d957a1ee40837f46aa30f0f4c657e673ad86a2e6362a9f9be20d26d9/aiohttp-3.14.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:53e5179d8abb5710f8e83ba207c41c8d1261fcffd4616500e15ca2b7a33be10a", size = 1713940, upload-time = "2026-07-23T01:56:15.969Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/38/05/d33c680c1bcf1c7e130f9cbfc1fc02fe8bb0c4af2a94a53dd5fb56131e5c/aiohttp-3.14.3-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:cd817772b2fcf2b8c0905795318485f9ec16eae60b29feb7f4c77085311637f0", size = 1724413, upload-time = "2026-07-23T01:56:18.591Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/85/1d/af798d306f7a74b6a632dbcabcf62a4c91391b7582d2a8c6d7712e2cc54e/aiohttp-3.14.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:4e3ac92d90e92773b2362d506068e9a948192bd553e743c5b2429e28527c8661", size = 1770748, upload-time = "2026-07-23T01:56:21.074Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/a8/92/ad720d472556a995049206867765e9410969684f86ee09423ff9969044c1/aiohttp-3.14.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:3f42e9b78301f11c8f861746175d8b9c1ccef713fcad9eab396e2f6db8ed4a22", size = 1577564, upload-time = "2026-07-23T01:56:23.475Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/60/ad/0ed7586cbef7a884e23a752fa2bb987a122e6a5dd50dab109258d0a95193/aiohttp-3.14.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:9d9edccfe496b476db5f398d97b865e9a6752bcf8aec4eef8390ce20fb64bb41", size = 1782080, upload-time = "2026-07-23T01:56:25.994Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/97/ea/dbaed0d73e8a69aad653b045dab451c67c2454bb731a37b45a86593e9422/aiohttp-3.14.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:1c5ec8fb1bcc31a8466f74aaf26c345d5c386fa4bd08a3f0eb9c7a4a3fe8b5bf", size = 1745813, upload-time = "2026-07-23T01:56:28.604Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/81/1b/6893d4bc57e434fc93a6c9217c637d967a0b651d989f6e3265179375754a/aiohttp-3.14.3-cp314-cp314-win32.whl", hash = "sha256:38901a84da3ce22249f6e860bf8f90d141bcab7da090cc398f8bb58c0e44b7da", size = 455872, upload-time = "2026-07-23T01:56:31.031Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/f5/8b/c7baa1ba1eda4db6989baefe5de6d99834921b84ebd7918624febcb9f290/aiohttp-3.14.3-cp314-cp314-win_amd64.whl", hash = "sha256:8b3b60de05f3dcb6f6a00f818bb2ec781cee4de0645f59ccaf99b1d1823b6100", size = 481030, upload-time = "2026-07-23T01:56:33.365Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/22/8c/c29d067df825a2df88ca432db848aa2fe8199598359cc06c12b09320cac9/aiohttp-3.14.3-cp314-cp314-win_arm64.whl", hash = "sha256:1576145bdceeb92382d899751e12743a3a5b8e460a841e3e50543859e54864dc", size = 453669, upload-time = "2026-07-23T01:56:35.731Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/6a/a4/9c033beb355d39b6147980597ec9645e4729243f686ee4dc73945de72030/aiohttp-3.14.3-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:8800c996b01c2772a783e3e46f3e1abd5823029adca0df54231960de9bfefa5b", size = 791403, upload-time = "2026-07-23T01:56:37.972Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/80/ca/87c32a0a7704583cfc49660bd817889bae5b830bf53b5dcb4e92145ac2da/aiohttp-3.14.3-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:ebe8e504f058fe91223351cecd2d9d6946c9d241bb0250d898ffbdf584cc72b0", size = 526413, upload-time = "2026-07-23T01:56:40.523Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/9e/d8/8ec0e471248c500acdce2be3f46db8fb62b5eb60efef072529cc85ee1d26/aiohttp-3.14.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:30402d03a7c0ff52bce290b57e564e9079fd9d0cb545c8aba73f86a103162d2e", size = 532135, upload-time = "2026-07-23T01:56:42.876Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/fe/45/f8919fd936e8b79fcd9bda7b6d8e62613462a713f4f17987fd7c34399142/aiohttp-3.14.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9fc7b5bfec6573f3ae844f457fdde5adeb713f8b8e4a81ad64fc207b49383716", size = 1922742, upload-time = "2026-07-23T01:56:45.528Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/f6/ec/9ca76b28a27525b0cc53e20842e0228b022f301ce1f436b7d814b4aaf2df/aiohttp-3.14.3-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8a5fd34f7f7410d1730d5c2ba873cacb2eed3fede366feb268a70ba22581ed8f", size = 1787371, upload-time = "2026-07-23T01:56:48.045Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/b1/04/6acdbf17315f7b55f1937e3387acb89a3cddeb4995689553d064af8e92ab/aiohttp-3.14.3-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:270d3dace9ca2f10f0da5d8ebe519b7a310fc6112ed916e32df5866df0888553", size = 1912623, upload-time = "2026-07-23T01:56:50.605Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/86/e6/438b0c79ca6f45eb9fd9817dd4c01a91919a38c0de5ee9e05e2b4dc0ece7/aiohttp-3.14.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3ae5b3a59436d089b5395d910121a390feed4d00578eb95a0fd1a329fe963100", size = 2005515, upload-time = "2026-07-23T01:56:53.153Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/bb/6b/62cbd6577758699525f5c712d1ddef57d9875fbab0ae8d5f5a202fd598f8/aiohttp-3.14.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2498f0fe69ead802f9675beca44a7c21c62fdaa4ec5145ea1c3ad6edbee29f85", size = 1879906, upload-time = "2026-07-23T01:56:55.818Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/00/95/18bcbf830a21dc3aae24d8f6b6feaf3db1d2090242d00a7868db2ffb0b67/aiohttp-3.14.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a0dc483c00da8b673abbb367eb6f8d8f4bcec30eb58529ea13cb42e7fd2dfa33", size = 1675849, upload-time = "2026-07-23T01:56:58.861Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/a9/19/47f4968659c5e23606c3790c80fc624e691c153d036148449ee84d31b287/aiohttp-3.14.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c7d3a97c678d34fc5b59da671ee9cd630096ddc643e7b5a30d54a2a6f3574d3f", size = 1843496, upload-time = "2026-07-23T01:57:01.591Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/64/af/38c33c4dd82fddcb4e56c4653b6f1072a8edbc6b7fa15809f14932c41e2d/aiohttp-3.14.3-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:f8fb78a83c9e5f741ca3a68cfb455c1f5bb83b4e7249a3848b3cd78d0a8563b0", size = 1827746, upload-time = "2026-07-23T01:57:05.131Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/a1/9d/0537cda4885ac8f5b7053d164dd06312f4c483a4edcb8ee5b8aaf2a989bf/aiohttp-3.14.3-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:74ab5b6a9fb13e873e5a90946588baecaf488745e1db1a4a5c433f971f035098", size = 1853810, upload-time = "2026-07-23T01:57:08.043Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/19/fe/26f9c5e6458385aa86497836b0dea6fb2f027827d63f37c7856cce9286ee/aiohttp-3.14.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:bd52f811e65f6fb634b1047159657c98f52b407f8efec907bcfc09da9a4c0a25", size = 1668895, upload-time = "2026-07-23T01:57:10.837Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/ec/4c/618b1db9b9ba079b8875d2cdf78e7c4a3bf72903bd5850fee7dd9544600a/aiohttp-3.14.3-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:f0f177d1b195b9e06376cfd7d308d8a1b920909a609d03ac82a8c73bbb16d3b9", size = 1883833, upload-time = "2026-07-23T01:57:13.672Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/94/c6/bd959bd1e4771f9fd944e9e436224c48c77b018b73b519b5aad346335bcc/aiohttp-3.14.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:498c6c623134f8e09a3c4e60bcd607a0b4590dd7dbf08dd40851b27cbb520ccb", size = 1844251, upload-time = "2026-07-23T01:57:16.593Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/5e/19/08d41839658bdd44a0ed2480f3891705ecb487ce28c0dde62c9040c997e0/aiohttp-3.14.3-cp314-cp314t-win32.whl", hash = "sha256:b304db572b4368edd8dda8a2274f73156fe15558fca4a917cb8a09fc47af5963", size = 474180, upload-time = "2026-07-23T01:57:19.306Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/99/5d/3cd6ef0a2b2851f7ab913b5b079334781bd50ff56a323e4454063377a080/aiohttp-3.14.3-cp314-cp314t-win_amd64.whl", hash = "sha256:b20032766aedf6261c7a566585a40867d092ac03a0d81592d5370ef9b054f99b", size = 500528, upload-time = "2026-07-23T01:57:21.762Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/a4/37/cfd1ed540a4d318da025590d96b728e63713c09e9377950fc655dadeb856/aiohttp-3.14.3-cp314-cp314t-win_arm64.whl", hash = "sha256:2e1161602f45a54de2ce0905243a95f58cb42dcd378402f3697f5e0b21e9d2e7", size = 469280, upload-time = "2026-07-23T01:57:24.241Z" },
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "aiosignal"
|
|
||||||
version = "1.4.0"
|
|
||||||
source = { registry = "https://pypi.org/simple" }
|
|
||||||
dependencies = [
|
|
||||||
{ name = "frozenlist" },
|
|
||||||
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
|
||||||
]
|
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/61/62/06741b579156360248d1ec624842ad0edf697050bbaf7c3e46394e106ad1/aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7", size = 25007, upload-time = "2025-07-03T22:54:43.528Z" }
|
|
||||||
wheels = [
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490, upload-time = "2025-07-03T22:54:42.156Z" },
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "alembic"
|
name = "alembic"
|
||||||
version = "1.19.1"
|
version = "1.19.1"
|
||||||
@@ -174,15 +52,6 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl", hash = "sha256:9f505dda5ac9f0c8309b5e8bd445a8c2bf7246f3ce950121e45ea15bc41d1494", size = 125813, upload-time = "2026-07-12T20:29:05.763Z" },
|
{ url = "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl", hash = "sha256:9f505dda5ac9f0c8309b5e8bd445a8c2bf7246f3ce950121e45ea15bc41d1494", size = 125813, upload-time = "2026-07-12T20:29:05.763Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "attrs"
|
|
||||||
version = "26.1.0"
|
|
||||||
source = { registry = "https://pypi.org/simple" }
|
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/9a/8e/82a0fe20a541c03148528be8cac2408564a6c9a0cc7e9171802bc1d26985/attrs-26.1.0.tar.gz", hash = "sha256:d03ceb89cb322a8fd706d4fb91940737b6642aa36998fe130a9bc96c985eff32", size = 952055, upload-time = "2026-03-19T14:22:25.026Z" }
|
|
||||||
wheels = [
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl", hash = "sha256:c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309", size = 67548, upload-time = "2026-03-19T14:22:23.645Z" },
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "backoff"
|
name = "backoff"
|
||||||
version = "2.2.1"
|
version = "2.2.1"
|
||||||
@@ -598,7 +467,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dagster"
|
name = "dagster"
|
||||||
version = "1.13.19"
|
version = "1.12.8"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "alembic" },
|
{ name = "alembic" },
|
||||||
@@ -619,6 +488,7 @@ dependencies = [
|
|||||||
{ name = "pywin32", marker = "sys_platform == 'win32'" },
|
{ name = "pywin32", marker = "sys_platform == 'win32'" },
|
||||||
{ name = "requests" },
|
{ name = "requests" },
|
||||||
{ name = "rich" },
|
{ name = "rich" },
|
||||||
|
{ name = "setuptools" },
|
||||||
{ name = "six" },
|
{ name = "six" },
|
||||||
{ name = "sqlalchemy" },
|
{ name = "sqlalchemy" },
|
||||||
{ name = "structlog" },
|
{ name = "structlog" },
|
||||||
@@ -630,14 +500,14 @@ dependencies = [
|
|||||||
{ name = "universal-pathlib" },
|
{ name = "universal-pathlib" },
|
||||||
{ name = "watchdog" },
|
{ name = "watchdog" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/0b/3e/23ebd048231c36c7c063a7d972756268ef714deedb58366134a4d3c94ef7/dagster-1.13.19.tar.gz", hash = "sha256:c2b3d06c198dc3bd99be7b2c0ec5022c919b1acf20c058bf652f2498e0119ec7", size = 3629331, upload-time = "2026-08-21T15:12:15.466Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/65/03/a5108fe3b882fe40baa1d34da6f2fe292ac5a75db9a8c7254de8b51a4e5a/dagster-1.12.8.tar.gz", hash = "sha256:38551907f2f261d63f290a364df9fea5abbf3e38cf64f837a8ef2afdd80f9d34", size = 1566204, upload-time = "2025-12-29T19:10:21.207Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/aa/46/8dbed1a3dc6299b5e92525ae29295ee264902343b0ad7297a4f537d4ef7f/dagster-1.13.19-py3-none-any.whl", hash = "sha256:22896569d6b371f42394ea36961e9fcc485f61c795aed2a733634979ce74f86b", size = 2025984, upload-time = "2026-08-21T15:12:12.95Z" },
|
{ url = "https://files.pythonhosted.org/packages/a7/50/44e8fb3c2f67b252bbab83f4048a1f6f668c1e73eb8ca5fe19233b271786/dagster-1.12.8-py3-none-any.whl", hash = "sha256:102eb110762fb9c2db7443a7d5df2863f32054eb764db575074421ff16706813", size = 1950472, upload-time = "2025-12-29T19:10:18.876Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dagster-graphql"
|
name = "dagster-graphql"
|
||||||
version = "1.13.19"
|
version = "1.12.8"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "dagster" },
|
{ name = "dagster" },
|
||||||
@@ -646,50 +516,50 @@ dependencies = [
|
|||||||
{ name = "requests" },
|
{ name = "requests" },
|
||||||
{ name = "starlette" },
|
{ name = "starlette" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/a1/fb/f0e76e0b276de31f84cc6687aeeb01cd27d15dbdf65d739400e3110bf691/dagster_graphql-1.13.19.tar.gz", hash = "sha256:30ffbfbb0e7b17a3c6dabfb2887ed0c5c8da13bccf239f1bc3e3252683f08484", size = 695728, upload-time = "2026-08-21T15:13:01.058Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/c3/0e/515c2966532410a1d3b7427c00cc6fc3bc6061ef64327a25a437e20b070a/dagster_graphql-1.12.8.tar.gz", hash = "sha256:b732bcdc91fc4874b5aa2e3572f16b169764ddbf10498aabf14593f185b40473", size = 158881, upload-time = "2025-12-29T19:10:37.456Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/6e/09/ecd0a13a34a22930a723035d683960892d0b58d988bfc677c930233880d3/dagster_graphql-1.13.19-py3-none-any.whl", hash = "sha256:276a27cd1c09d226775cff509a31dfba582d430712c33af662695a1643c897c2", size = 228534, upload-time = "2026-08-21T15:12:59.746Z" },
|
{ url = "https://files.pythonhosted.org/packages/f1/7b/81fe0eed6f88cd3084e25b8bc9090881e53a2eddd2de676c39a04c71d019/dagster_graphql-1.12.8-py3-none-any.whl", hash = "sha256:5ae8ea80d5bb94ef70ab6e87d3c8f55e1570fa8402ffffb1e85fa28c34502b7c", size = 206012, upload-time = "2025-12-29T19:10:36.294Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dagster-k8s"
|
name = "dagster-k8s"
|
||||||
version = "0.29.19"
|
version = "0.28.8"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "dagster" },
|
{ name = "dagster" },
|
||||||
{ name = "google-auth" },
|
{ name = "google-auth" },
|
||||||
{ name = "kubernetes" },
|
{ name = "kubernetes" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/94/06/38a258c3570d754df8c9768cc13fdb844046f7a4259b3ce64cd61cce0ccd/dagster_k8s-0.29.19.tar.gz", hash = "sha256:1d4b0e69f3fcff0704ffbce5a9554811163ff5df0a14059d566695041b928848", size = 309360, upload-time = "2026-08-21T15:22:56.758Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/19/4d/19337f52238cd0ec071d381dc5030ff4928613f930c1e8601ef7f4a7e538/dagster_k8s-0.28.8.tar.gz", hash = "sha256:edd6af1476b3ef5c2d37da6217ea02f9756bda5fcd53e1c808aceab3e4662a4c", size = 51513, upload-time = "2025-12-29T19:21:42.738Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/e0/b5/0472da80caffa94dbebac98791fda6d51c9995889960e77a5dfb77db4a3e/dagster_k8s-0.29.19-py3-none-any.whl", hash = "sha256:cabe40918a895bd6c0ef8c12a875bd4eb68be9915ce337a618672593a35c2da4", size = 57796, upload-time = "2026-08-21T15:22:55.422Z" },
|
{ url = "https://files.pythonhosted.org/packages/0a/cf/d324ca38d738c96af17e2a65c2337281dd2583ea8cc55179ccbec3688a6c/dagster_k8s-0.28.8-py3-none-any.whl", hash = "sha256:6864b26a38f8bb2048eabd2a2aa8a930ca57481b95407fe1143e8460d1cf652f", size = 56616, upload-time = "2025-12-29T19:21:41.653Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dagster-pipes"
|
name = "dagster-pipes"
|
||||||
version = "1.13.19"
|
version = "1.12.8"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/43/f7/a7c6f1c347ae01d2eaa8dbdc36f927a71a19481f1d180c10d297b4044ba5/dagster_pipes-1.13.19.tar.gz", hash = "sha256:df0c3b3582dec0bdd2f19acd12672c2923d5601d35f66b222a2780d3c7247a0d", size = 149679, upload-time = "2026-08-21T15:12:49.982Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/1f/63/2eb5eb7a18683d9feebb023140ed10935570d3c23f6b62aa50616fbb0bb0/dagster_pipes-1.12.8.tar.gz", hash = "sha256:0c590e3e42e2f94eaa013af7f8f049bca58962e4d013758f84d8608e4bc668a1", size = 21091, upload-time = "2025-12-29T19:10:32.306Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/e7/54/0dc0f7404eca8c9759336f3cee562b59851197e3c7c1b65ce5047d774165/dagster_pipes-1.13.19-py3-none-any.whl", hash = "sha256:3a4af8d4e72f1b8da673fabf53d1e598236e1274f77327de790e31aab00b8df8", size = 20242, upload-time = "2026-08-21T15:12:48.903Z" },
|
{ url = "https://files.pythonhosted.org/packages/7b/82/6fd7fede962812656f6f279e43e45b62f42c1e9c8f0d6b745ab3bb43ee87/dagster_pipes-1.12.8-py3-none-any.whl", hash = "sha256:12fa5049c5719b2b83c8702031779833cc5f34e8da270cf8483958378ba104c1", size = 20839, upload-time = "2025-12-29T19:10:31.051Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dagster-postgres"
|
name = "dagster-postgres"
|
||||||
version = "0.29.19"
|
version = "0.28.8"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "dagster" },
|
{ name = "dagster" },
|
||||||
{ name = "psycopg2-binary" },
|
{ name = "psycopg2-binary" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/e4/28/5c59e5227268d0330837f3dfe699e6733a85fc6ab0638c8c7e972a4668ad/dagster_postgres-0.29.19.tar.gz", hash = "sha256:3cd350b716faf492210f9541bbcdc70eea90df3b0a69cd8d4dff514af1ac6b31", size = 406345, upload-time = "2026-08-21T15:22:18.789Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/e0/54/0f681df1d31f88dc4ef514a323957bdc139af3ff0df006010131a6940cef/dagster_postgres-0.28.8.tar.gz", hash = "sha256:3a5957445792294000454b2a56b81c2e607a18248abc522ccf53cca794e5f682", size = 16456, upload-time = "2025-12-29T19:19:23.51Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/db/49/8f62e575a5a560ded18247b355a4a037a0fea501fdcd86bc06a422f81093/dagster_postgres-0.29.19-py3-none-any.whl", hash = "sha256:8a89aecbec1a0e4bea6abe766ffa9f3e06b9779885b5914f8d072b1bebd9c89f", size = 25558, upload-time = "2026-08-21T15:22:17.716Z" },
|
{ url = "https://files.pythonhosted.org/packages/75/80/d063bf1d4a489b84a33b84c138822b15ae01729082db0b9d11e895549bf6/dagster_postgres-0.28.8-py3-none-any.whl", hash = "sha256:ae21b163d6ba2c2b5b73b724ab5b0b6ef4434aa6ed4e7106fa6a91fa03f969a0", size = 22944, upload-time = "2025-12-29T19:19:22.464Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dagster-shared"
|
name = "dagster-shared"
|
||||||
version = "1.13.19"
|
version = "1.12.8"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "packaging" },
|
{ name = "packaging" },
|
||||||
@@ -699,14 +569,14 @@ dependencies = [
|
|||||||
{ name = "tomlkit" },
|
{ name = "tomlkit" },
|
||||||
{ name = "typing-extensions" },
|
{ name = "typing-extensions" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/6b/d3/5c6090138b27a51c9f92722a05e4fe0f1eebbf1f14badd8ef5d4e32f84ba/dagster_shared-1.13.19.tar.gz", hash = "sha256:76f920b20866e28092fe02983dca4bfba55bd8596b5f5c20429343dfb5d7a39a", size = 124096, upload-time = "2026-08-21T15:27:12.517Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/78/5c/7f5463895c357117bf9285452e5525c54f4aca02ac331b20817d08cdd938/dagster_shared-1.12.8.tar.gz", hash = "sha256:b22beeb43dd0a6da8744a2409fd1c56f0864da81fb7a59b7b97db2d520b0eff8", size = 78154, upload-time = "2025-12-29T19:20:42.532Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/2a/5d/938ba2c23f0b19938b1bad63f03a2bb12a1c43175c02db99dbc3c024542f/dagster_shared-1.13.19-py3-none-any.whl", hash = "sha256:35653847a031ebcf4f9e1b37b4f509938d18adf1088b2331a44182ccf124a898", size = 96420, upload-time = "2026-08-21T15:27:11.392Z" },
|
{ url = "https://files.pythonhosted.org/packages/54/55/15b8aa49fd4b9cf0eccd13b19a63b024a782fea1890667c0db9045f84793/dagster_shared-1.12.8-py3-none-any.whl", hash = "sha256:1522a8da2f821014e9307bd03f5e9d9d9dbe657d74de3742501f3538b8d36572", size = 91408, upload-time = "2025-12-29T19:20:41.609Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dagster-webserver"
|
name = "dagster-webserver"
|
||||||
version = "1.13.19"
|
version = "1.12.8"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "click" },
|
{ name = "click" },
|
||||||
@@ -715,9 +585,9 @@ dependencies = [
|
|||||||
{ name = "starlette" },
|
{ name = "starlette" },
|
||||||
{ name = "uvicorn", extra = ["standard"] },
|
{ name = "uvicorn", extra = ["standard"] },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/40/9c/12017b879d2e8893fe749617e0154e03d0edbbee9591d419bfa865b1669c/dagster_webserver-1.13.19.tar.gz", hash = "sha256:4192e80321623975b3cff4623aba48a4dbc63dc48d01f37f4be160a31d3dffa9", size = 12366742, upload-time = "2026-08-21T15:20:08.722Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/60/3d/f96da5c164b337b763b75e0c084bd52be95eaa2a60d021261e90d9d06b10/dagster_webserver-1.12.8.tar.gz", hash = "sha256:c12ed724cc6258f948cd0e3800cf9ff01e986e73b9eca6e923cf75a2f98aa5de", size = 12241193, upload-time = "2025-12-29T19:18:24.8Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/6a/08/dec5071faa1e0c33f0b78c1ac4ff37a37ab469f8e93451f4e972c6ef9828/dagster_webserver-1.13.19-py3-none-any.whl", hash = "sha256:65115560fd197a6ead94e4a25d141447d10238fc650540f0f0fa61cd48c3d4ad", size = 12516446, upload-time = "2026-08-21T15:20:06.387Z" },
|
{ url = "https://files.pythonhosted.org/packages/cb/94/1ba8d099c25e2a14a0d3923c137ea971827f8dd3fae475310b6f77917c21/dagster_webserver-1.12.8-py3-none-any.whl", hash = "sha256:49a64df19d420c398593ff7582e1dd8cf0dbf02a9752e52aed6e758490364de2", size = 12582830, upload-time = "2025-12-29T19:18:22.46Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -741,10 +611,10 @@ dev = [
|
|||||||
|
|
||||||
[package.metadata]
|
[package.metadata]
|
||||||
requires-dist = [
|
requires-dist = [
|
||||||
{ name = "dagster" },
|
{ name = "dagster", specifier = "==1.12.8" },
|
||||||
{ name = "dagster-k8s", specifier = ">=0.27.16" },
|
{ name = "dagster-k8s", specifier = "==0.28.8" },
|
||||||
{ name = "dagster-postgres", specifier = ">=0.27.16" },
|
{ name = "dagster-postgres", specifier = "==0.28.8" },
|
||||||
{ name = "dagster-webserver", specifier = ">=1.11.16" },
|
{ name = "dagster-webserver", specifier = "==1.12.8" },
|
||||||
{ name = "pip", specifier = ">=26.1.2" },
|
{ name = "pip", specifier = ">=26.1.2" },
|
||||||
{ name = "pydantic", specifier = ">=2.0" },
|
{ name = "pydantic", specifier = ">=2.0" },
|
||||||
]
|
]
|
||||||
@@ -782,95 +652,6 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/01/a4/9b63d595d748e3aff8812b65eacc1a2c4bd90b7c2012e08e72373b4835eb/filelock-3.32.4-py3-none-any.whl", hash = "sha256:22e58ca3b1ae3b98993b762d7338367ae64fe50252bf78d59da3bfebcdf1cedd", size = 99864, upload-time = "2026-08-23T17:37:53.913Z" },
|
{ url = "https://files.pythonhosted.org/packages/01/a4/9b63d595d748e3aff8812b65eacc1a2c4bd90b7c2012e08e72373b4835eb/filelock-3.32.4-py3-none-any.whl", hash = "sha256:22e58ca3b1ae3b98993b762d7338367ae64fe50252bf78d59da3bfebcdf1cedd", size = 99864, upload-time = "2026-08-23T17:37:53.913Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "frozenlist"
|
|
||||||
version = "1.8.0"
|
|
||||||
source = { registry = "https://pypi.org/simple" }
|
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/2d/f5/c831fac6cc817d26fd54c7eaccd04ef7e0288806943f7cc5bbf69f3ac1f0/frozenlist-1.8.0.tar.gz", hash = "sha256:3ede829ed8d842f6cd48fc7081d7a41001a56f1f38603f9d49bf3020d59a31ad", size = 45875, upload-time = "2025-10-06T05:38:17.865Z" }
|
|
||||||
wheels = [
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/69/29/948b9aa87e75820a38650af445d2ef2b6b8a6fab1a23b6bb9e4ef0be2d59/frozenlist-1.8.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:78f7b9e5d6f2fdb88cdde9440dc147259b62b9d3b019924def9f6478be254ac1", size = 87782, upload-time = "2025-10-06T05:36:06.649Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/64/80/4f6e318ee2a7c0750ed724fa33a4bdf1eacdc5a39a7a24e818a773cd91af/frozenlist-1.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:229bf37d2e4acdaf808fd3f06e854a4a7a3661e871b10dc1f8f1896a3b05f18b", size = 50594, upload-time = "2025-10-06T05:36:07.69Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/2b/94/5c8a2b50a496b11dd519f4a24cb5496cf125681dd99e94c604ccdea9419a/frozenlist-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f833670942247a14eafbb675458b4e61c82e002a148f49e68257b79296e865c4", size = 50448, upload-time = "2025-10-06T05:36:08.78Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/6a/bd/d91c5e39f490a49df14320f4e8c80161cfcce09f1e2cde1edd16a551abb3/frozenlist-1.8.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:494a5952b1c597ba44e0e78113a7266e656b9794eec897b19ead706bd7074383", size = 242411, upload-time = "2025-10-06T05:36:09.801Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/8f/83/f61505a05109ef3293dfb1ff594d13d64a2324ac3482be2cedc2be818256/frozenlist-1.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96f423a119f4777a4a056b66ce11527366a8bb92f54e541ade21f2374433f6d4", size = 243014, upload-time = "2025-10-06T05:36:11.394Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/d8/cb/cb6c7b0f7d4023ddda30cf56b8b17494eb3a79e3fda666bf735f63118b35/frozenlist-1.8.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3462dd9475af2025c31cc61be6652dfa25cbfb56cbbf52f4ccfe029f38decaf8", size = 234909, upload-time = "2025-10-06T05:36:12.598Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/31/c5/cd7a1f3b8b34af009fb17d4123c5a778b44ae2804e3ad6b86204255f9ec5/frozenlist-1.8.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4c800524c9cd9bac5166cd6f55285957fcfc907db323e193f2afcd4d9abd69b", size = 250049, upload-time = "2025-10-06T05:36:14.065Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/c0/01/2f95d3b416c584a1e7f0e1d6d31998c4a795f7544069ee2e0962a4b60740/frozenlist-1.8.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d6a5df73acd3399d893dafc71663ad22534b5aa4f94e8a2fabfe856c3c1b6a52", size = 256485, upload-time = "2025-10-06T05:36:15.39Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/ce/03/024bf7720b3abaebcff6d0793d73c154237b85bdf67b7ed55e5e9596dc9a/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:405e8fe955c2280ce66428b3ca55e12b3c4e9c336fb2103a4937e891c69a4a29", size = 237619, upload-time = "2025-10-06T05:36:16.558Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/69/fa/f8abdfe7d76b731f5d8bd217827cf6764d4f1d9763407e42717b4bed50a0/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:908bd3f6439f2fef9e85031b59fd4f1297af54415fb60e4254a95f75b3cab3f3", size = 250320, upload-time = "2025-10-06T05:36:17.821Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/f5/3c/b051329f718b463b22613e269ad72138cc256c540f78a6de89452803a47d/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:294e487f9ec720bd8ffcebc99d575f7eff3568a08a253d1ee1a0378754b74143", size = 246820, upload-time = "2025-10-06T05:36:19.046Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/0f/ae/58282e8f98e444b3f4dd42448ff36fa38bef29e40d40f330b22e7108f565/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:74c51543498289c0c43656701be6b077f4b265868fa7f8a8859c197006efb608", size = 250518, upload-time = "2025-10-06T05:36:20.763Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/8f/96/007e5944694d66123183845a106547a15944fbbb7154788cbf7272789536/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:776f352e8329135506a1d6bf16ac3f87bc25b28e765949282dcc627af36123aa", size = 239096, upload-time = "2025-10-06T05:36:22.129Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/66/bb/852b9d6db2fa40be96f29c0d1205c306288f0684df8fd26ca1951d461a56/frozenlist-1.8.0-cp312-cp312-win32.whl", hash = "sha256:433403ae80709741ce34038da08511d4a77062aa924baf411ef73d1146e74faf", size = 39985, upload-time = "2025-10-06T05:36:23.661Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/b8/af/38e51a553dd66eb064cdf193841f16f077585d4d28394c2fa6235cb41765/frozenlist-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:34187385b08f866104f0c0617404c8eb08165ab1272e884abc89c112e9c00746", size = 44591, upload-time = "2025-10-06T05:36:24.958Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/a7/06/1dc65480ab147339fecc70797e9c2f69d9cea9cf38934ce08df070fdb9cb/frozenlist-1.8.0-cp312-cp312-win_arm64.whl", hash = "sha256:fe3c58d2f5db5fbd18c2987cba06d51b0529f52bc3a6cdc33d3f4eab725104bd", size = 40102, upload-time = "2025-10-06T05:36:26.333Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/2d/40/0832c31a37d60f60ed79e9dfb5a92e1e2af4f40a16a29abcc7992af9edff/frozenlist-1.8.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8d92f1a84bb12d9e56f818b3a746f3efba93c1b63c8387a73dde655e1e42282a", size = 85717, upload-time = "2025-10-06T05:36:27.341Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/30/ba/b0b3de23f40bc55a7057bd38434e25c34fa48e17f20ee273bbde5e0650f3/frozenlist-1.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:96153e77a591c8adc2ee805756c61f59fef4cf4073a9275ee86fe8cba41241f7", size = 49651, upload-time = "2025-10-06T05:36:28.855Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/0c/ab/6e5080ee374f875296c4243c381bbdef97a9ac39c6e3ce1d5f7d42cb78d6/frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f21f00a91358803399890ab167098c131ec2ddd5f8f5fd5fe9c9f2c6fcd91e40", size = 49417, upload-time = "2025-10-06T05:36:29.877Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/d5/4e/e4691508f9477ce67da2015d8c00acd751e6287739123113a9fca6f1604e/frozenlist-1.8.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fb30f9626572a76dfe4293c7194a09fb1fe93ba94c7d4f720dfae3b646b45027", size = 234391, upload-time = "2025-10-06T05:36:31.301Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/40/76/c202df58e3acdf12969a7895fd6f3bc016c642e6726aa63bd3025e0fc71c/frozenlist-1.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eaa352d7047a31d87dafcacbabe89df0aa506abb5b1b85a2fb91bc3faa02d822", size = 233048, upload-time = "2025-10-06T05:36:32.531Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/f9/c0/8746afb90f17b73ca5979c7a3958116e105ff796e718575175319b5bb4ce/frozenlist-1.8.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:03ae967b4e297f58f8c774c7eabcce57fe3c2434817d4385c50661845a058121", size = 226549, upload-time = "2025-10-06T05:36:33.706Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/7e/eb/4c7eefc718ff72f9b6c4893291abaae5fbc0c82226a32dcd8ef4f7a5dbef/frozenlist-1.8.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f6292f1de555ffcc675941d65fffffb0a5bcd992905015f85d0592201793e0e5", size = 239833, upload-time = "2025-10-06T05:36:34.947Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/c2/4e/e5c02187cf704224f8b21bee886f3d713ca379535f16893233b9d672ea71/frozenlist-1.8.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29548f9b5b5e3460ce7378144c3010363d8035cea44bc0bf02d57f5a685e084e", size = 245363, upload-time = "2025-10-06T05:36:36.534Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/1f/96/cb85ec608464472e82ad37a17f844889c36100eed57bea094518bf270692/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ec3cc8c5d4084591b4237c0a272cc4f50a5b03396a47d9caaf76f5d7b38a4f11", size = 229314, upload-time = "2025-10-06T05:36:38.582Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/5d/6f/4ae69c550e4cee66b57887daeebe006fe985917c01d0fff9caab9883f6d0/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:517279f58009d0b1f2e7c1b130b377a349405da3f7621ed6bfae50b10adf20c1", size = 243365, upload-time = "2025-10-06T05:36:40.152Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/7a/58/afd56de246cf11780a40a2c28dc7cbabbf06337cc8ddb1c780a2d97e88d8/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:db1e72ede2d0d7ccb213f218df6a078a9c09a7de257c2fe8fcef16d5925230b1", size = 237763, upload-time = "2025-10-06T05:36:41.355Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/cb/36/cdfaf6ed42e2644740d4a10452d8e97fa1c062e2a8006e4b09f1b5fd7d63/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b4dec9482a65c54a5044486847b8a66bf10c9cb4926d42927ec4e8fd5db7fed8", size = 240110, upload-time = "2025-10-06T05:36:42.716Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/03/a8/9ea226fbefad669f11b52e864c55f0bd57d3c8d7eb07e9f2e9a0b39502e1/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:21900c48ae04d13d416f0e1e0c4d81f7931f73a9dfa0b7a8746fb2fe7dd970ed", size = 233717, upload-time = "2025-10-06T05:36:44.251Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/1e/0b/1b5531611e83ba7d13ccc9988967ea1b51186af64c42b7a7af465dcc9568/frozenlist-1.8.0-cp313-cp313-win32.whl", hash = "sha256:8b7b94a067d1c504ee0b16def57ad5738701e4ba10cec90529f13fa03c833496", size = 39628, upload-time = "2025-10-06T05:36:45.423Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/d8/cf/174c91dbc9cc49bc7b7aab74d8b734e974d1faa8f191c74af9b7e80848e6/frozenlist-1.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:878be833caa6a3821caf85eb39c5ba92d28e85df26d57afb06b35b2efd937231", size = 43882, upload-time = "2025-10-06T05:36:46.796Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/c1/17/502cd212cbfa96eb1388614fe39a3fc9ab87dbbe042b66f97acb57474834/frozenlist-1.8.0-cp313-cp313-win_arm64.whl", hash = "sha256:44389d135b3ff43ba8cc89ff7f51f5a0bb6b63d829c8300f79a2fe4fe61bcc62", size = 39676, upload-time = "2025-10-06T05:36:47.8Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/d2/5c/3bbfaa920dfab09e76946a5d2833a7cbdf7b9b4a91c714666ac4855b88b4/frozenlist-1.8.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:e25ac20a2ef37e91c1b39938b591457666a0fa835c7783c3a8f33ea42870db94", size = 89235, upload-time = "2025-10-06T05:36:48.78Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/d2/d6/f03961ef72166cec1687e84e8925838442b615bd0b8854b54923ce5b7b8a/frozenlist-1.8.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:07cdca25a91a4386d2e76ad992916a85038a9b97561bf7a3fd12d5d9ce31870c", size = 50742, upload-time = "2025-10-06T05:36:49.837Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/1e/bb/a6d12b7ba4c3337667d0e421f7181c82dda448ce4e7ad7ecd249a16fa806/frozenlist-1.8.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4e0c11f2cc6717e0a741f84a527c52616140741cd812a50422f83dc31749fb52", size = 51725, upload-time = "2025-10-06T05:36:50.851Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/bc/71/d1fed0ffe2c2ccd70b43714c6cab0f4188f09f8a67a7914a6b46ee30f274/frozenlist-1.8.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b3210649ee28062ea6099cfda39e147fa1bc039583c8ee4481cb7811e2448c51", size = 284533, upload-time = "2025-10-06T05:36:51.898Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/c9/1f/fb1685a7b009d89f9bf78a42d94461bc06581f6e718c39344754a5d9bada/frozenlist-1.8.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:581ef5194c48035a7de2aefc72ac6539823bb71508189e5de01d60c9dcd5fa65", size = 292506, upload-time = "2025-10-06T05:36:53.101Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/e6/3b/b991fe1612703f7e0d05c0cf734c1b77aaf7c7d321df4572e8d36e7048c8/frozenlist-1.8.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3ef2d026f16a2b1866e1d86fc4e1291e1ed8a387b2c333809419a2f8b3a77b82", size = 274161, upload-time = "2025-10-06T05:36:54.309Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/ca/ec/c5c618767bcdf66e88945ec0157d7f6c4a1322f1473392319b7a2501ded7/frozenlist-1.8.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5500ef82073f599ac84d888e3a8c1f77ac831183244bfd7f11eaa0289fb30714", size = 294676, upload-time = "2025-10-06T05:36:55.566Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/7c/ce/3934758637d8f8a88d11f0585d6495ef54b2044ed6ec84492a91fa3b27aa/frozenlist-1.8.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:50066c3997d0091c411a66e710f4e11752251e6d2d73d70d8d5d4c76442a199d", size = 300638, upload-time = "2025-10-06T05:36:56.758Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/fc/4f/a7e4d0d467298f42de4b41cbc7ddaf19d3cfeabaf9ff97c20c6c7ee409f9/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:5c1c8e78426e59b3f8005e9b19f6ff46e5845895adbde20ece9218319eca6506", size = 283067, upload-time = "2025-10-06T05:36:57.965Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/dc/48/c7b163063d55a83772b268e6d1affb960771b0e203b632cfe09522d67ea5/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:eefdba20de0d938cec6a89bd4d70f346a03108a19b9df4248d3cf0d88f1b0f51", size = 292101, upload-time = "2025-10-06T05:36:59.237Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/9f/d0/2366d3c4ecdc2fd391e0afa6e11500bfba0ea772764d631bbf82f0136c9d/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:cf253e0e1c3ceb4aaff6df637ce033ff6535fb8c70a764a8f46aafd3d6ab798e", size = 289901, upload-time = "2025-10-06T05:37:00.811Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/b8/94/daff920e82c1b70e3618a2ac39fbc01ae3e2ff6124e80739ce5d71c9b920/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:032efa2674356903cd0261c4317a561a6850f3ac864a63fc1583147fb05a79b0", size = 289395, upload-time = "2025-10-06T05:37:02.115Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/e3/20/bba307ab4235a09fdcd3cc5508dbabd17c4634a1af4b96e0f69bfe551ebd/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6da155091429aeba16851ecb10a9104a108bcd32f6c1642867eadaee401c1c41", size = 283659, upload-time = "2025-10-06T05:37:03.711Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/fd/00/04ca1c3a7a124b6de4f8a9a17cc2fcad138b4608e7a3fc5877804b8715d7/frozenlist-1.8.0-cp313-cp313t-win32.whl", hash = "sha256:0f96534f8bfebc1a394209427d0f8a63d343c9779cda6fc25e8e121b5fd8555b", size = 43492, upload-time = "2025-10-06T05:37:04.915Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/59/5e/c69f733a86a94ab10f68e496dc6b7e8bc078ebb415281d5698313e3af3a1/frozenlist-1.8.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5d63a068f978fc69421fb0e6eb91a9603187527c86b7cd3f534a5b77a592b888", size = 48034, upload-time = "2025-10-06T05:37:06.343Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/16/6c/be9d79775d8abe79b05fa6d23da99ad6e7763a1d080fbae7290b286093fd/frozenlist-1.8.0-cp313-cp313t-win_arm64.whl", hash = "sha256:bf0a7e10b077bf5fb9380ad3ae8ce20ef919a6ad93b4552896419ac7e1d8e042", size = 41749, upload-time = "2025-10-06T05:37:07.431Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/f1/c8/85da824b7e7b9b6e7f7705b2ecaf9591ba6f79c1177f324c2735e41d36a2/frozenlist-1.8.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:cee686f1f4cadeb2136007ddedd0aaf928ab95216e7691c63e50a8ec066336d0", size = 86127, upload-time = "2025-10-06T05:37:08.438Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/8e/e8/a1185e236ec66c20afd72399522f142c3724c785789255202d27ae992818/frozenlist-1.8.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:119fb2a1bd47307e899c2fac7f28e85b9a543864df47aa7ec9d3c1b4545f096f", size = 49698, upload-time = "2025-10-06T05:37:09.48Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/a1/93/72b1736d68f03fda5fdf0f2180fb6caaae3894f1b854d006ac61ecc727ee/frozenlist-1.8.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4970ece02dbc8c3a92fcc5228e36a3e933a01a999f7094ff7c23fbd2beeaa67c", size = 49749, upload-time = "2025-10-06T05:37:10.569Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/a7/b2/fabede9fafd976b991e9f1b9c8c873ed86f202889b864756f240ce6dd855/frozenlist-1.8.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:cba69cb73723c3f329622e34bdbf5ce1f80c21c290ff04256cff1cd3c2036ed2", size = 231298, upload-time = "2025-10-06T05:37:11.993Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/3a/3b/d9b1e0b0eed36e70477ffb8360c49c85c8ca8ef9700a4e6711f39a6e8b45/frozenlist-1.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:778a11b15673f6f1df23d9586f83c4846c471a8af693a22e066508b77d201ec8", size = 232015, upload-time = "2025-10-06T05:37:13.194Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/dc/94/be719d2766c1138148564a3960fc2c06eb688da592bdc25adcf856101be7/frozenlist-1.8.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0325024fe97f94c41c08872db482cf8ac4800d80e79222c6b0b7b162d5b13686", size = 225038, upload-time = "2025-10-06T05:37:14.577Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/e4/09/6712b6c5465f083f52f50cf74167b92d4ea2f50e46a9eea0523d658454ae/frozenlist-1.8.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:97260ff46b207a82a7567b581ab4190bd4dfa09f4db8a8b49d1a958f6aa4940e", size = 240130, upload-time = "2025-10-06T05:37:15.781Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/f8/d4/cd065cdcf21550b54f3ce6a22e143ac9e4836ca42a0de1022da8498eac89/frozenlist-1.8.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:54b2077180eb7f83dd52c40b2750d0a9f175e06a42e3213ce047219de902717a", size = 242845, upload-time = "2025-10-06T05:37:17.037Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/62/c3/f57a5c8c70cd1ead3d5d5f776f89d33110b1addae0ab010ad774d9a44fb9/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2f05983daecab868a31e1da44462873306d3cbfd76d1f0b5b69c473d21dbb128", size = 229131, upload-time = "2025-10-06T05:37:18.221Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/6c/52/232476fe9cb64f0742f3fde2b7d26c1dac18b6d62071c74d4ded55e0ef94/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:33f48f51a446114bc5d251fb2954ab0164d5be02ad3382abcbfe07e2531d650f", size = 240542, upload-time = "2025-10-06T05:37:19.771Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/5f/85/07bf3f5d0fb5414aee5f47d33c6f5c77bfe49aac680bfece33d4fdf6a246/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:154e55ec0655291b5dd1b8731c637ecdb50975a2ae70c606d100750a540082f7", size = 237308, upload-time = "2025-10-06T05:37:20.969Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/11/99/ae3a33d5befd41ac0ca2cc7fd3aa707c9c324de2e89db0e0f45db9a64c26/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:4314debad13beb564b708b4a496020e5306c7333fa9a3ab90374169a20ffab30", size = 238210, upload-time = "2025-10-06T05:37:22.252Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/b2/60/b1d2da22f4970e7a155f0adde9b1435712ece01b3cd45ba63702aea33938/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:073f8bf8becba60aa931eb3bc420b217bb7d5b8f4750e6f8b3be7f3da85d38b7", size = 231972, upload-time = "2025-10-06T05:37:23.5Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/3f/ab/945b2f32de889993b9c9133216c068b7fcf257d8595a0ac420ac8677cab0/frozenlist-1.8.0-cp314-cp314-win32.whl", hash = "sha256:bac9c42ba2ac65ddc115d930c78d24ab8d4f465fd3fc473cdedfccadb9429806", size = 40536, upload-time = "2025-10-06T05:37:25.581Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/59/ad/9caa9b9c836d9ad6f067157a531ac48b7d36499f5036d4141ce78c230b1b/frozenlist-1.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:3e0761f4d1a44f1d1a47996511752cf3dcec5bbdd9cc2b4fe595caf97754b7a0", size = 44330, upload-time = "2025-10-06T05:37:26.928Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/82/13/e6950121764f2676f43534c555249f57030150260aee9dcf7d64efda11dd/frozenlist-1.8.0-cp314-cp314-win_arm64.whl", hash = "sha256:d1eaff1d00c7751b7c6662e9c5ba6eb2c17a2306ba5e2a37f24ddf3cc953402b", size = 40627, upload-time = "2025-10-06T05:37:28.075Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/c0/c7/43200656ecc4e02d3f8bc248df68256cd9572b3f0017f0a0c4e93440ae23/frozenlist-1.8.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:d3bb933317c52d7ea5004a1c442eef86f426886fba134ef8cf4226ea6ee1821d", size = 89238, upload-time = "2025-10-06T05:37:29.373Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/d1/29/55c5f0689b9c0fb765055629f472c0de484dcaf0acee2f7707266ae3583c/frozenlist-1.8.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:8009897cdef112072f93a0efdce29cd819e717fd2f649ee3016efd3cd885a7ed", size = 50738, upload-time = "2025-10-06T05:37:30.792Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2c5dcbbc55383e5883246d11fd179782a9d07a986c40f49abe89ddf865913930", size = 51739, upload-time = "2025-10-06T05:37:32.127Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/62/1c/3d8622e60d0b767a5510d1d3cf21065b9db874696a51ea6d7a43180a259c/frozenlist-1.8.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:39ecbc32f1390387d2aa4f5a995e465e9e2f79ba3adcac92d68e3e0afae6657c", size = 284186, upload-time = "2025-10-06T05:37:33.21Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/2d/14/aa36d5f85a89679a85a1d44cd7a6657e0b1c75f61e7cad987b203d2daca8/frozenlist-1.8.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92db2bf818d5cc8d9c1f1fc56b897662e24ea5adb36ad1f1d82875bd64e03c24", size = 292196, upload-time = "2025-10-06T05:37:36.107Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/05/23/6bde59eb55abd407d34f77d39a5126fb7b4f109a3f611d3929f14b700c66/frozenlist-1.8.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2dc43a022e555de94c3b68a4ef0b11c4f747d12c024a520c7101709a2144fb37", size = 273830, upload-time = "2025-10-06T05:37:37.663Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/d2/3f/22cff331bfad7a8afa616289000ba793347fcd7bc275f3b28ecea2a27909/frozenlist-1.8.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cb89a7f2de3602cfed448095bab3f178399646ab7c61454315089787df07733a", size = 294289, upload-time = "2025-10-06T05:37:39.261Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/a4/89/5b057c799de4838b6c69aa82b79705f2027615e01be996d2486a69ca99c4/frozenlist-1.8.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:33139dc858c580ea50e7e60a1b0ea003efa1fd42e6ec7fdbad78fff65fad2fd2", size = 300318, upload-time = "2025-10-06T05:37:43.213Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/30/de/2c22ab3eb2a8af6d69dc799e48455813bab3690c760de58e1bf43b36da3e/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:168c0969a329b416119507ba30b9ea13688fafffac1b7822802537569a1cb0ef", size = 282814, upload-time = "2025-10-06T05:37:45.337Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/59/f7/970141a6a8dbd7f556d94977858cfb36fa9b66e0892c6dd780d2219d8cd8/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:28bd570e8e189d7f7b001966435f9dac6718324b5be2990ac496cf1ea9ddb7fe", size = 291762, upload-time = "2025-10-06T05:37:46.657Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/c1/15/ca1adae83a719f82df9116d66f5bb28bb95557b3951903d39135620ef157/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b2a095d45c5d46e5e79ba1e5b9cb787f541a8dee0433836cea4b96a2c439dcd8", size = 289470, upload-time = "2025-10-06T05:37:47.946Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/ac/83/dca6dc53bf657d371fbc88ddeb21b79891e747189c5de990b9dfff2ccba1/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:eab8145831a0d56ec9c4139b6c3e594c7a83c2c8be25d5bcf2d86136a532287a", size = 289042, upload-time = "2025-10-06T05:37:49.499Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/96/52/abddd34ca99be142f354398700536c5bd315880ed0a213812bc491cff5e4/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:974b28cf63cc99dfb2188d8d222bc6843656188164848c4f679e63dae4b0708e", size = 283148, upload-time = "2025-10-06T05:37:50.745Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/af/d3/76bd4ed4317e7119c2b7f57c3f6934aba26d277acc6309f873341640e21f/frozenlist-1.8.0-cp314-cp314t-win32.whl", hash = "sha256:342c97bf697ac5480c0a7ec73cd700ecfa5a8a40ac923bd035484616efecc2df", size = 44676, upload-time = "2025-10-06T05:37:52.222Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/89/76/c615883b7b521ead2944bb3480398cbb07e12b7b4e4d073d3752eb721558/frozenlist-1.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:06be8f67f39c8b1dc671f5d83aaefd3358ae5cdcf8314552c57e7ed3e6475bdd", size = 49451, upload-time = "2025-10-06T05:37:53.425Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/e0/a3/5982da14e113d07b325230f95060e2169f5311b1017ea8af2a29b374c289/frozenlist-1.8.0-cp314-cp314t-win_arm64.whl", hash = "sha256:102e6314ca4da683dca92e3b1355490fed5f313b768500084fbe6371fddfdb79", size = 42507, upload-time = "2025-10-06T05:37:54.513Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/9a/9a/e35b4a917281c0b8419d4207f4334c8e8c5dbf4f3f5f9ada73958d937dcc/frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d", size = 13409, upload-time = "2025-10-06T05:38:16.721Z" },
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fsspec"
|
name = "fsspec"
|
||||||
version = "2026.7.0"
|
version = "2026.7.0"
|
||||||
@@ -1148,12 +929,12 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kubernetes"
|
name = "kubernetes"
|
||||||
version = "36.0.3"
|
version = "34.1.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "aiohttp" },
|
|
||||||
{ name = "certifi" },
|
{ name = "certifi" },
|
||||||
{ name = "durationpy" },
|
{ name = "durationpy" },
|
||||||
|
{ name = "google-auth" },
|
||||||
{ name = "python-dateutil" },
|
{ name = "python-dateutil" },
|
||||||
{ name = "pyyaml" },
|
{ name = "pyyaml" },
|
||||||
{ name = "requests" },
|
{ name = "requests" },
|
||||||
@@ -1162,9 +943,9 @@ dependencies = [
|
|||||||
{ name = "urllib3" },
|
{ name = "urllib3" },
|
||||||
{ name = "websocket-client" },
|
{ name = "websocket-client" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/ca/57/b07b96353f902aa1bdbe00e878e3a12a137977d03a962479785576aa8ec9/kubernetes-36.0.3.tar.gz", hash = "sha256:36993ed25ce59b789c9341473a228fcf268504a2fec7c2b2b1531d73072e5ce7", size = 2337528, upload-time = "2026-07-13T20:38:12.128Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/ef/55/3f880ef65f559cbed44a9aa20d3bdbc219a2c3a3bac4a30a513029b03ee9/kubernetes-34.1.0.tar.gz", hash = "sha256:8fe8edb0b5d290a2f3ac06596b23f87c658977d46b5f8df9d0f4ea83d0003912", size = 1083771, upload-time = "2025-09-29T20:23:49.283Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/5b/30/a96d47df739689ac0001ade0afefc16e3b477fc2fb426b568515fdc8afce/kubernetes-36.0.3-py2.py3-none-any.whl", hash = "sha256:8fde9241c4b298e6374a069dcf728359b4e72c2fb29489a975ba4e1c047cf10f", size = 4618066, upload-time = "2026-07-13T20:38:10.172Z" },
|
{ url = "https://files.pythonhosted.org/packages/ca/ec/65f7d563aa4a62dd58777e8f6aa882f15db53b14eb29aba0c28a20f7eb26/kubernetes-34.1.0-py2.py3-none-any.whl", hash = "sha256:bffba2272534e224e6a7a74d582deb0b545b7c9879d2cd9e4aae9481d1f2cc2a", size = 2008380, upload-time = "2025-09-29T20:23:47.684Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1896,6 +1677,15 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl", hash = "sha256:33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb", size = 310654, upload-time = "2026-04-12T08:24:02.83Z" },
|
{ url = "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl", hash = "sha256:33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb", size = 310654, upload-time = "2026-04-12T08:24:02.83Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "setuptools"
|
||||||
|
version = "84.0.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/6d/44/f5da03a8ef95d369145c5bb53050e7877c9f3d312e128605fd9504829143/setuptools-84.0.0.tar.gz", hash = "sha256:f4695c21257f0d9b537ec2692c941d02ee143b7cc1276941349a546573b2ef73", size = 1168449, upload-time = "2026-08-08T18:27:58.365Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/95/9c/c510029fc6ef33a6275cd2c5d3cecd6613dfd6aa401d57c54f1c18852ccf/setuptools-84.0.0-py3-none-any.whl", hash = "sha256:51a52592b3b99e102b609654876bd65f19f999935166d1352678931132b0c670", size = 818216, upload-time = "2026-08-08T18:27:56.719Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "six"
|
name = "six"
|
||||||
version = "1.17.0"
|
version = "1.17.0"
|
||||||
@@ -2091,11 +1881,11 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "urllib3"
|
name = "urllib3"
|
||||||
version = "2.7.0"
|
version = "2.3.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/53/0c/06f8b233b8fd13b9e5ee11424ef85419ba0d8ba0b3138bf360be2ff56953/urllib3-2.7.0.tar.gz", hash = "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c", size = 433602, upload-time = "2026-05-07T16:13:18.596Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/aa/63/e53da845320b757bf29ef6a9062f5c669fe997973f966045cb019c3f4b66/urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d", size = 307268, upload-time = "2024-12-22T07:47:30.032Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897", size = 131087, upload-time = "2026-05-07T16:13:17.151Z" },
|
{ url = "https://files.pythonhosted.org/packages/c8/19/4ec628951a74043532ca2cf5d97b7b14863931476d117c471e8e2b1eb39f/urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", size = 128369, upload-time = "2024-12-22T07:47:28.074Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
182
yaml/loosely-coupled/probe-pipes-k8s.yaml
Normal file
182
yaml/loosely-coupled/probe-pipes-k8s.yaml
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
# Cluster probe for the loosely coupled Kubernetes transport.
|
||||||
|
#
|
||||||
|
# Runs `loosely_coupled_k8s_job` from a single throwaway pod. The point is to
|
||||||
|
# prove the part of this service that no test can reach: that the dispatching
|
||||||
|
# process creates payload Jobs and that messages come back over the pod log
|
||||||
|
# stream. It clears readiness checks L4-L9 in one run.
|
||||||
|
#
|
||||||
|
# Deliberately NOT a Dagster deployment. No webserver, no daemon, no database,
|
||||||
|
# no code location registration. That sidesteps the control-plane version skew -
|
||||||
|
# the pod is its own control plane, so the 1.13.19 images here have nothing to be
|
||||||
|
# compatible with. Everything lives in one namespace you delete afterwards.
|
||||||
|
#
|
||||||
|
# --- Before applying -------------------------------------------------------
|
||||||
|
#
|
||||||
|
# Credentials, only if your registry needs them. The Gitea images referenced
|
||||||
|
# below do NOT: a bare GET returns 401, but that is the start of the Docker
|
||||||
|
# token handshake, and completing it anonymously returns the manifest. A probe
|
||||||
|
# pod carrying no credentials pulled and ran on the sandbox on 2026-08-31.
|
||||||
|
#
|
||||||
|
# If you point this at a registry that does require authentication, remember the
|
||||||
|
# payload Jobs need it too. PipesK8sClient sets no serviceAccountName, so they
|
||||||
|
# run as `default` and inherit nothing from the pod below; patch that account or
|
||||||
|
# pass imagePullSecrets through base_pod_spec in dispatch_external_work_k8s. A
|
||||||
|
# payload pod that cannot pull leaves the op waiting until pod_wait_timeout,
|
||||||
|
# which reads like a hung workload rather than a missing credential.
|
||||||
|
#
|
||||||
|
# kubectl apply -f yaml/loosely-coupled/probe-pipes-k8s.yaml
|
||||||
|
#
|
||||||
|
# On sandbox-cat-dat use yaml/sandbox/probe-pipes-k8s-sandbox.yaml instead: that
|
||||||
|
# cluster's access is Rancher project-scoped, so this file's namespace and RBAC
|
||||||
|
# cannot be created there. The sandbox variant needs neither.
|
||||||
|
#
|
||||||
|
# `--dry-run=server` reports "namespaces distexec-probe not found" for the four
|
||||||
|
# namespaced objects. That is the dry run declining to create the namespace it
|
||||||
|
# would need, not a fault in the manifests; `--dry-run=client` passes clean.
|
||||||
|
#
|
||||||
|
# LIMITATION under a restricted Pod Security namespace. This pod satisfies the
|
||||||
|
# restricted standard, but the payload Jobs do not: PipesK8sClient builds those
|
||||||
|
# pod specs and this service passes no securityContext through base_pod_spec, so
|
||||||
|
# such a namespace would admit the dispatcher and reject every payload it
|
||||||
|
# creates. Leave the probe namespace unlabelled, or add the fields to
|
||||||
|
# base_pod_spec in dispatch_external_work_k8s first.
|
||||||
|
#
|
||||||
|
# --- Reading the result ----------------------------------------------------
|
||||||
|
#
|
||||||
|
# kubectl -n distexec-probe logs -f job/pipes-probe
|
||||||
|
# kubectl -n distexec-probe get jobs -l app.kubernetes.io/name=distributed-execution-payload
|
||||||
|
#
|
||||||
|
# Success is RUN_SUCCESS plus four payload Jobs, one per work unit. The
|
||||||
|
# summarise_results output carries contributing_workers; on a cluster those
|
||||||
|
# should be four distinct pod hostnames, which is the claim the guide makes and
|
||||||
|
# a laptop cannot demonstrate.
|
||||||
|
#
|
||||||
|
# A run that reaches RUN_FAILURE with "no pipes messages received" means the
|
||||||
|
# payload ran but its log stream never came back - check the pods/log rule
|
||||||
|
# below before suspecting the payload.
|
||||||
|
#
|
||||||
|
# --- Teardown --------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# kubectl delete namespace distexec-probe
|
||||||
|
#
|
||||||
|
# NOT CLUSTER-VERIFIED. Written against the published images and the RBAC the
|
||||||
|
# pipes client is documented to need, but not yet applied to a cluster.
|
||||||
|
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: distexec-probe
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: distributed-execution
|
||||||
|
app.kubernetes.io/component: probe
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: pipes-dispatcher
|
||||||
|
namespace: distexec-probe
|
||||||
|
imagePullSecrets:
|
||||||
|
- name: gitea-registry
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: Role
|
||||||
|
metadata:
|
||||||
|
name: pipes-dispatcher
|
||||||
|
namespace: distexec-probe
|
||||||
|
rules:
|
||||||
|
- apiGroups: ["batch"]
|
||||||
|
resources: ["jobs", "jobs/status"]
|
||||||
|
verbs: ["create", "get", "list", "watch", "delete"]
|
||||||
|
# pods/log is the message channel for PipesK8sPodLogsMessageReader, not just
|
||||||
|
# an observability convenience. Without it the payload runs to completion and
|
||||||
|
# reports nothing, and the op fails on an empty message list.
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["pods", "pods/log", "pods/status"]
|
||||||
|
verbs: ["get", "list", "watch"]
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: RoleBinding
|
||||||
|
metadata:
|
||||||
|
name: pipes-dispatcher
|
||||||
|
namespace: distexec-probe
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: pipes-dispatcher
|
||||||
|
namespace: distexec-probe
|
||||||
|
roleRef:
|
||||||
|
kind: Role
|
||||||
|
name: pipes-dispatcher
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
---
|
||||||
|
apiVersion: batch/v1
|
||||||
|
kind: Job
|
||||||
|
metadata:
|
||||||
|
name: pipes-probe
|
||||||
|
namespace: distexec-probe
|
||||||
|
spec:
|
||||||
|
# One shot. A retry would obscure which attempt produced which payload Jobs.
|
||||||
|
backoffLimit: 0
|
||||||
|
activeDeadlineSeconds: 1800
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: distributed-execution
|
||||||
|
app.kubernetes.io/component: probe
|
||||||
|
spec:
|
||||||
|
restartPolicy: Never
|
||||||
|
serviceAccountName: pipes-dispatcher
|
||||||
|
# A service account with automountServiceAccountToken: false - which the
|
||||||
|
# platform's dagster-svc-account uses - leaves the pipes client selecting
|
||||||
|
# in-cluster auth and then failing on "Service token file does not exist".
|
||||||
|
automountServiceAccountToken: true
|
||||||
|
securityContext:
|
||||||
|
runAsNonRoot: true
|
||||||
|
runAsUser: 1000
|
||||||
|
runAsGroup: 1000
|
||||||
|
# Makes the emptyDir writable by UID 1000, which DAGSTER_HOME needs.
|
||||||
|
fsGroup: 1000
|
||||||
|
seccompProfile:
|
||||||
|
type: RuntimeDefault
|
||||||
|
containers:
|
||||||
|
- name: dispatcher
|
||||||
|
image: gitea.dataprovider01.sandbox-cat-dat.simpl-europe.eu/j.r/distributed-execution:5122da4691f9
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
# Satisfies the restricted Pod Security standard. The int cluster did
|
||||||
|
# not enforce it when this was written and the sandbox was not checked;
|
||||||
|
# a cluster that does enforce it rejects the pod outright.
|
||||||
|
securityContext:
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
capabilities:
|
||||||
|
drop:
|
||||||
|
- ALL
|
||||||
|
command:
|
||||||
|
- dagster
|
||||||
|
- job
|
||||||
|
- execute
|
||||||
|
- -f
|
||||||
|
- src/distributed_execution/repository.py
|
||||||
|
- -j
|
||||||
|
- loosely_coupled_k8s_job
|
||||||
|
env:
|
||||||
|
- name: DAGSTER_HOME
|
||||||
|
value: /dagster-home
|
||||||
|
# Must be the same commit as the image above.
|
||||||
|
- name: PIPES_PAYLOAD_IMAGE
|
||||||
|
value: gitea.dataprovider01.sandbox-cat-dat.simpl-europe.eu/j.r/distributed-execution-payload:5122da4691f9
|
||||||
|
- name: PIPES_PAYLOAD_NAMESPACE
|
||||||
|
value: distexec-probe
|
||||||
|
volumeMounts:
|
||||||
|
- name: dagster-home
|
||||||
|
mountPath: /dagster-home
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 200m
|
||||||
|
memory: 512Mi
|
||||||
|
limits:
|
||||||
|
cpu: "1"
|
||||||
|
memory: 1Gi
|
||||||
|
volumes:
|
||||||
|
# The job runs on multiprocess_executor, so the instance has to be a real
|
||||||
|
# sqlite instance on disk rather than an ephemeral one.
|
||||||
|
- name: dagster-home
|
||||||
|
emptyDir: {}
|
||||||
@@ -6,6 +6,18 @@
|
|||||||
# Contrast with yaml/tightly-coupled/values-run-launcher.yaml: there, every
|
# Contrast with yaml/tightly-coupled/values-run-launcher.yaml: there, every
|
||||||
# execution pod needed S3 and Vault credentials. Here the payload needs none -
|
# execution pod needed S3 and Vault credentials. Here the payload needs none -
|
||||||
# only the dispatching pod does.
|
# only the dispatching pod does.
|
||||||
|
#
|
||||||
|
# VERSION LOCK. The payload tag below must equal the code location image tag in
|
||||||
|
# yaml/values-dagster-distributed-execution.yaml. The two images share a commit:
|
||||||
|
# the dispatching op and payload/work.py agree on the `units` extras key and on
|
||||||
|
# the custom-message shape, and nothing at runtime checks that agreement. A
|
||||||
|
# mismatched pair surfaces as "no pipes messages received", which reads like a
|
||||||
|
# broken message channel rather than a version skew.
|
||||||
|
#
|
||||||
|
# For values that work today, see yaml/sandbox/values-sandbox-gitea.yaml. The
|
||||||
|
# shared GitLab pipeline (ds.gitlab-ci.yml) builds exactly one image per project -
|
||||||
|
# $CI_REGISTRY_IMAGE from the root Dockerfile - so the payload reference below
|
||||||
|
# resolves only once that pipeline learns to build a second image.
|
||||||
|
|
||||||
dagster:
|
dagster:
|
||||||
dagster-user-deployments:
|
dagster-user-deployments:
|
||||||
@@ -14,7 +26,8 @@ dagster:
|
|||||||
envSecrets: []
|
envSecrets: []
|
||||||
env:
|
env:
|
||||||
- name: PIPES_PAYLOAD_IMAGE
|
- name: PIPES_PAYLOAD_IMAGE
|
||||||
value: code.europa.eu:4567/simpl/simpl-open/data/supporting-data-services/distributed-execution/payload:0.1.0
|
# DO NOT CHANGE the tag - replaced automatically by the pipeline before releasing
|
||||||
|
value: code.europa.eu:4567/simpl/simpl-open/data/supporting-data-services/distributed-execution/distributed-execution/payload:0.0.0
|
||||||
- name: PIPES_PAYLOAD_NAMESPACE
|
- name: PIPES_PAYLOAD_NAMESPACE
|
||||||
value: dagster
|
value: dagster
|
||||||
|
|
||||||
@@ -27,6 +40,7 @@ dagster:
|
|||||||
containerConfig:
|
containerConfig:
|
||||||
env:
|
env:
|
||||||
- name: PIPES_PAYLOAD_IMAGE
|
- name: PIPES_PAYLOAD_IMAGE
|
||||||
value: code.europa.eu:4567/simpl/simpl-open/data/supporting-data-services/distributed-execution/payload:0.1.0
|
# DO NOT CHANGE the tag - replaced automatically by the pipeline before releasing
|
||||||
|
value: code.europa.eu:4567/simpl/simpl-open/data/supporting-data-services/distributed-execution/distributed-execution/payload:0.0.0
|
||||||
- name: PIPES_PAYLOAD_NAMESPACE
|
- name: PIPES_PAYLOAD_NAMESPACE
|
||||||
value: dagster
|
value: dagster
|
||||||
|
|||||||
161
yaml/sandbox/probe-k8s-executor-sandbox.yaml
Normal file
161
yaml/sandbox/probe-k8s-executor-sandbox.yaml
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
# T6/T7 probe - tightly coupled via k8s_job_executor, one pod per step.
|
||||||
|
#
|
||||||
|
# This is the invasive one. Unlike the pipes probe it writes to the platform's
|
||||||
|
# live metadata database, because that is what tightly coupled means: every step
|
||||||
|
# pod opens the database itself, so they must share instance storage. Safe only
|
||||||
|
# because the images are pinned to dagster 1.12.8, exactly matching the control
|
||||||
|
# plane, so no schema migration can be triggered.
|
||||||
|
#
|
||||||
|
# Two things the loosely coupled probe did not need:
|
||||||
|
#
|
||||||
|
# 1. Shared instance storage. DAGSTER_HOME is copied from the platform's
|
||||||
|
# `dagster-instance` ConfigMap into a writable volume, so run and event
|
||||||
|
# storage are the same Postgres the platform uses. Step pods get the same
|
||||||
|
# config via the run launcher's `instance_config_map`.
|
||||||
|
#
|
||||||
|
# 2. A shared I/O manager. The default writes step outputs to pod-local disk,
|
||||||
|
# which under this executor means a downstream step cannot read an upstream
|
||||||
|
# output. base_dir is redirected to the RWX `dagster-shared-pvc` the
|
||||||
|
# launcher already declares.
|
||||||
|
#
|
||||||
|
# The run config lives in its own ConfigMap rather than a heredoc inside the
|
||||||
|
# container command. A heredoc nested in a YAML block scalar silently produced an
|
||||||
|
# empty file on the first attempt, and an empty run config is valid YAML, so the
|
||||||
|
# run started and only failed later with "No image included in either executor
|
||||||
|
# config or the job" - a confusing distance from the actual cause. The command
|
||||||
|
# echoes the config before using it so that failure mode cannot recur silently.
|
||||||
|
#
|
||||||
|
# --- Running ---------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# kubectl -n dataprovider01 apply -f yaml/sandbox/probe-k8s-executor-sandbox.yaml
|
||||||
|
# kubectl -n dataprovider01 logs -f job/distexec-k8sexec-probe
|
||||||
|
# kubectl -n dataprovider01 get jobs -l dagster/job=tightly_coupled_k8s_job # T6
|
||||||
|
#
|
||||||
|
# --- Teardown --------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# kubectl -n dataprovider01 delete job distexec-k8sexec-probe
|
||||||
|
# kubectl -n dataprovider01 delete jobs -l dagster/job=tightly_coupled_k8s_job
|
||||||
|
# kubectl -n dataprovider01 delete cm distexec-probe-run-config
|
||||||
|
#
|
||||||
|
# The run itself stays in the platform's Dagster database and will be visible in
|
||||||
|
# its UI. That is not reversible with kubectl.
|
||||||
|
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: distexec-probe-run-config
|
||||||
|
namespace: dataprovider01
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: distributed-execution
|
||||||
|
app.kubernetes.io/component: probe
|
||||||
|
data:
|
||||||
|
run-config.yaml: |
|
||||||
|
execution:
|
||||||
|
config:
|
||||||
|
job_namespace: dataprovider01
|
||||||
|
job_image: gitea.dataprovider01.sandbox-cat-dat.simpl-europe.eu/j.r/distributed-execution:3f8175a17f0a
|
||||||
|
service_account_name: dagster-svc-account
|
||||||
|
image_pull_policy: IfNotPresent
|
||||||
|
max_concurrent: 2
|
||||||
|
# Step pods inherit DAGSTER_HOME from the launching process otherwise,
|
||||||
|
# which points at a volume only that pod has.
|
||||||
|
env_vars:
|
||||||
|
- DAGSTER_HOME=/dagster/shared/distexec-probe/home
|
||||||
|
volumes:
|
||||||
|
- name: dagster-shared-storage
|
||||||
|
persistent_volume_claim:
|
||||||
|
claim_name: dagster-shared-pvc
|
||||||
|
volume_mounts:
|
||||||
|
- name: dagster-shared-storage
|
||||||
|
mount_path: /dagster/shared
|
||||||
|
step_k8s_config:
|
||||||
|
pod_spec_config:
|
||||||
|
automount_service_account_token: true
|
||||||
|
---
|
||||||
|
apiVersion: batch/v1
|
||||||
|
kind: Job
|
||||||
|
metadata:
|
||||||
|
name: distexec-k8sexec-probe
|
||||||
|
namespace: dataprovider01
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: distributed-execution
|
||||||
|
app.kubernetes.io/component: probe
|
||||||
|
spec:
|
||||||
|
backoffLimit: 0
|
||||||
|
activeDeadlineSeconds: 1800
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: distributed-execution
|
||||||
|
app.kubernetes.io/component: probe
|
||||||
|
spec:
|
||||||
|
restartPolicy: Never
|
||||||
|
serviceAccountName: dagster-svc-account
|
||||||
|
automountServiceAccountToken: true
|
||||||
|
securityContext:
|
||||||
|
runAsNonRoot: true
|
||||||
|
runAsUser: 1000
|
||||||
|
runAsGroup: 1000
|
||||||
|
fsGroup: 1000
|
||||||
|
seccompProfile:
|
||||||
|
type: RuntimeDefault
|
||||||
|
containers:
|
||||||
|
- name: runner
|
||||||
|
image: gitea.dataprovider01.sandbox-cat-dat.simpl-europe.eu/j.r/distributed-execution:3f8175a17f0a
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
securityContext:
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
capabilities:
|
||||||
|
drop:
|
||||||
|
- ALL
|
||||||
|
env:
|
||||||
|
# On the RWX volume, not a pod-local one: the default I/O manager writes
|
||||||
|
# step outputs under $DAGSTER_HOME/storage, and every step pod has to
|
||||||
|
# read what the previous one wrote.
|
||||||
|
- name: DAGSTER_HOME
|
||||||
|
value: /dagster/shared/distexec-probe/home
|
||||||
|
# How the chart tells a code location which image its steps run as.
|
||||||
|
- name: DAGSTER_CURRENT_IMAGE
|
||||||
|
value: gitea.dataprovider01.sandbox-cat-dat.simpl-europe.eu/j.r/distributed-execution:3f8175a17f0a
|
||||||
|
- name: DAGSTER_PG_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: dagster-postgresql-secret
|
||||||
|
key: postgresql-password
|
||||||
|
command:
|
||||||
|
- sh
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
set -e
|
||||||
|
mkdir -p "$DAGSTER_HOME"
|
||||||
|
cp /instance-cm/dagster.yaml "$DAGSTER_HOME/dagster.yaml"
|
||||||
|
echo "===== run config in use ====="
|
||||||
|
cat /run-config/run-config.yaml
|
||||||
|
echo "===== T6/T7: tightly_coupled_k8s_job ====="
|
||||||
|
dagster job execute -f src/distributed_execution/repository.py -j tightly_coupled_k8s_job -c /run-config/run-config.yaml
|
||||||
|
volumeMounts:
|
||||||
|
- name: instance-cm
|
||||||
|
mountPath: /instance-cm
|
||||||
|
readOnly: true
|
||||||
|
- name: run-config
|
||||||
|
mountPath: /run-config
|
||||||
|
readOnly: true
|
||||||
|
- name: dagster-shared-storage
|
||||||
|
mountPath: /dagster/shared
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 200m
|
||||||
|
memory: 512Mi
|
||||||
|
limits:
|
||||||
|
cpu: "1"
|
||||||
|
memory: 1Gi
|
||||||
|
volumes:
|
||||||
|
- name: instance-cm
|
||||||
|
configMap:
|
||||||
|
name: dagster-instance
|
||||||
|
- name: run-config
|
||||||
|
configMap:
|
||||||
|
name: distexec-probe-run-config
|
||||||
|
- name: dagster-shared-storage
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: dagster-shared-pvc
|
||||||
124
yaml/sandbox/probe-pipes-k8s-sandbox.yaml
Normal file
124
yaml/sandbox/probe-pipes-k8s-sandbox.yaml
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
# Sandbox variant of the pipes cluster probe.
|
||||||
|
#
|
||||||
|
# Runs `loosely_coupled_k8s_job` as a single Job in dataprovider01, reusing the
|
||||||
|
# platform's own dagster-svc-account. Use this instead of
|
||||||
|
# yaml/loosely-coupled/probe-pipes-k8s.yaml on sandbox-cat-dat.
|
||||||
|
#
|
||||||
|
# WHY IT LOOKS DIFFERENT. The generic probe creates its own namespace, service
|
||||||
|
# account and RBAC. That cannot run here: sandbox access is Rancher
|
||||||
|
# project-scoped, so a freshly created namespace belongs to no project and the
|
||||||
|
# creator has no rights inside it, and `create roles` is denied in every
|
||||||
|
# namespace. Verified with `kubectl auth can-i`, not assumed.
|
||||||
|
#
|
||||||
|
# It does not need them anyway. The `dagster-role` bound to dagster-svc-account
|
||||||
|
# already grants batch/jobs (full verbs), jobs/status, pods, events, and
|
||||||
|
# pods/log - exactly the set the pipes client needs. Readiness checks L5 and L6
|
||||||
|
# therefore already pass on this cluster; read the live Role to confirm:
|
||||||
|
#
|
||||||
|
# kubectl -n dataprovider01 get role dagster-role -o yaml
|
||||||
|
#
|
||||||
|
# WHAT THIS COSTS. Unlike the generic probe this is NOT isolated. It borrows a
|
||||||
|
# live service account and leaves payload Jobs in a shared namespace until they
|
||||||
|
# are deleted. Nothing it does is persistent, but it is visible to anyone else
|
||||||
|
# working in dataprovider01.
|
||||||
|
#
|
||||||
|
# --- Credentials: none needed ----------------------------------------------
|
||||||
|
#
|
||||||
|
# Both Gitea images are anonymously pullable. A bare GET to the registry returns
|
||||||
|
# 401, which looks like a refusal but is just the start of the Docker token
|
||||||
|
# handshake; completing it anonymously and re-requesting the manifest returns
|
||||||
|
# 200 for both images. Verify with:
|
||||||
|
#
|
||||||
|
# TOK=$(curl -sS "https://gitea.dataprovider01.sandbox-cat-dat.simpl-europe.eu/v2/token?service=container_registry&scope=repository:j.r/distributed-execution:pull" | jq -r .token)
|
||||||
|
# curl -sS -o /dev/null -w '%{http_code}\n' -H "Authorization: Bearer $TOK" \
|
||||||
|
# https://gitea.dataprovider01.sandbox-cat-dat.simpl-europe.eu/v2/j.r/distributed-execution/manifests/5122da4691f9
|
||||||
|
#
|
||||||
|
# This also means the payload Jobs need nothing: they run as the `default`
|
||||||
|
# service account, which carries no pull secret, and do not need one.
|
||||||
|
#
|
||||||
|
# --- Running ---------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# kubectl -n dataprovider01 apply -f yaml/sandbox/probe-pipes-k8s-sandbox.yaml
|
||||||
|
# kubectl -n dataprovider01 logs -f job/distexec-pipes-probe
|
||||||
|
# kubectl -n dataprovider01 get jobs -l app.kubernetes.io/name=distributed-execution-payload
|
||||||
|
#
|
||||||
|
# --- Teardown --------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# kubectl -n dataprovider01 delete job distexec-pipes-probe
|
||||||
|
# kubectl -n dataprovider01 delete jobs -l app.kubernetes.io/name=distributed-execution-payload
|
||||||
|
#
|
||||||
|
# VERIFIED 2026-08-31 on sandbox-cat-dat / dataprovider01. Run
|
||||||
|
# cff9b348-bfc3-4ac1-ab51-a94892b8e3a0 reached RUN_SUCCESS: four payload Jobs,
|
||||||
|
# four distinct payload pod hostnames in contributing_hosts, messages returned
|
||||||
|
# over the pod log stream. Checks L4-L10 pass. Torn down afterwards; the
|
||||||
|
# namespace was left as it was found.
|
||||||
|
|
||||||
|
apiVersion: batch/v1
|
||||||
|
kind: Job
|
||||||
|
metadata:
|
||||||
|
name: distexec-pipes-probe
|
||||||
|
namespace: dataprovider01
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: distributed-execution
|
||||||
|
app.kubernetes.io/component: probe
|
||||||
|
spec:
|
||||||
|
backoffLimit: 0
|
||||||
|
activeDeadlineSeconds: 1800
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: distributed-execution
|
||||||
|
app.kubernetes.io/component: probe
|
||||||
|
spec:
|
||||||
|
restartPolicy: Never
|
||||||
|
# Already holds jobs + pods/log; this probe grants itself nothing.
|
||||||
|
serviceAccountName: dagster-svc-account
|
||||||
|
# dagster-svc-account sets automountServiceAccountToken: false, so every
|
||||||
|
# pod that uses it must opt back in - the chart does this for its own
|
||||||
|
# deployments. Without it the pipes client picks in-cluster auth correctly
|
||||||
|
# and then fails on "Service token file does not exist".
|
||||||
|
automountServiceAccountToken: true
|
||||||
|
securityContext:
|
||||||
|
runAsNonRoot: true
|
||||||
|
runAsUser: 1000
|
||||||
|
runAsGroup: 1000
|
||||||
|
fsGroup: 1000
|
||||||
|
seccompProfile:
|
||||||
|
type: RuntimeDefault
|
||||||
|
containers:
|
||||||
|
- name: dispatcher
|
||||||
|
image: gitea.dataprovider01.sandbox-cat-dat.simpl-europe.eu/j.r/distributed-execution:5122da4691f9
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
securityContext:
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
capabilities:
|
||||||
|
drop:
|
||||||
|
- ALL
|
||||||
|
command:
|
||||||
|
- dagster
|
||||||
|
- job
|
||||||
|
- execute
|
||||||
|
- -f
|
||||||
|
- src/distributed_execution/repository.py
|
||||||
|
- -j
|
||||||
|
- loosely_coupled_k8s_job
|
||||||
|
env:
|
||||||
|
- name: DAGSTER_HOME
|
||||||
|
value: /dagster-home
|
||||||
|
- name: PIPES_PAYLOAD_IMAGE
|
||||||
|
value: gitea.dataprovider01.sandbox-cat-dat.simpl-europe.eu/j.r/distributed-execution-payload:5122da4691f9
|
||||||
|
- name: PIPES_PAYLOAD_NAMESPACE
|
||||||
|
value: dataprovider01
|
||||||
|
volumeMounts:
|
||||||
|
- name: dagster-home
|
||||||
|
mountPath: /dagster-home
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 200m
|
||||||
|
memory: 512Mi
|
||||||
|
limits:
|
||||||
|
cpu: "1"
|
||||||
|
memory: 1Gi
|
||||||
|
volumes:
|
||||||
|
- name: dagster-home
|
||||||
|
emptyDir: {}
|
||||||
99
yaml/sandbox/probe-tightly-coupled-sandbox.yaml
Normal file
99
yaml/sandbox/probe-tightly-coupled-sandbox.yaml
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
# Tightly coupled probe for sandbox-cat-dat - the part that is safe to run.
|
||||||
|
#
|
||||||
|
# Covers T4 and proves the run pod can reach the metadata database, using a
|
||||||
|
# LOCAL SQLite instance. It deliberately does NOT write to the platform's
|
||||||
|
# Postgres. See "What this cannot cover" below.
|
||||||
|
#
|
||||||
|
# Runs three things in one pod:
|
||||||
|
# 1. A TCP probe to Postgres using this repository's own check_tcp_reachable.
|
||||||
|
# 2. tightly_coupled_in_process_job - single process, no fan-out.
|
||||||
|
# 3. tightly_coupled_local_job - multiprocess fan-out inside one pod (T4).
|
||||||
|
#
|
||||||
|
# --- What this cannot cover ------------------------------------------------
|
||||||
|
#
|
||||||
|
# T6 and T7 need `tightly_coupled_k8s_job`, and that cannot use a local SQLite
|
||||||
|
# instance: k8s_job_executor puts every step in its own pod, and each step pod
|
||||||
|
# opens the metadata database itself. That is the definition of tightly coupled.
|
||||||
|
# The step pods must therefore share instance storage, which means Postgres.
|
||||||
|
#
|
||||||
|
# The only Postgres available is `dataprovider01_dagster`, the platform's live
|
||||||
|
# metadata database, and these images carry dagster 1.13.19 against a control
|
||||||
|
# plane on 1.12.8. Pointing a newer Dagster at an older schema is not a safe
|
||||||
|
# operation on a shared database: at best it refuses to start with a schema
|
||||||
|
# mismatch, and it is not worth finding out the worse case on someone else's
|
||||||
|
# instance. Pin dagster to the control plane version and rebuild before trying.
|
||||||
|
#
|
||||||
|
# T1 is only partly covered. Its stated evidence expects DAGSTER_POSTGRES_HOST,
|
||||||
|
# DAGSTER_POSTGRES_USER and DAGSTER_POSTGRES_DB in the pod environment; the
|
||||||
|
# platform sets none of them - it passes DAGSTER_PG_PASSWORD and bakes the rest
|
||||||
|
# into dagster.yaml. Left unset here deliberately, so the run reports the real
|
||||||
|
# deployment's state rather than a flattering one.
|
||||||
|
#
|
||||||
|
# --- Running ---------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# kubectl -n dataprovider01 apply -f yaml/sandbox/probe-tightly-coupled-sandbox.yaml
|
||||||
|
# kubectl -n dataprovider01 logs -f job/distexec-tc-probe
|
||||||
|
# kubectl -n dataprovider01 delete job distexec-tc-probe
|
||||||
|
|
||||||
|
apiVersion: batch/v1
|
||||||
|
kind: Job
|
||||||
|
metadata:
|
||||||
|
name: distexec-tc-probe
|
||||||
|
namespace: dataprovider01
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: distributed-execution
|
||||||
|
app.kubernetes.io/component: probe
|
||||||
|
spec:
|
||||||
|
backoffLimit: 0
|
||||||
|
activeDeadlineSeconds: 1800
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: distributed-execution
|
||||||
|
app.kubernetes.io/component: probe
|
||||||
|
spec:
|
||||||
|
restartPolicy: Never
|
||||||
|
serviceAccountName: dagster-svc-account
|
||||||
|
automountServiceAccountToken: true
|
||||||
|
securityContext:
|
||||||
|
runAsNonRoot: true
|
||||||
|
runAsUser: 1000
|
||||||
|
runAsGroup: 1000
|
||||||
|
fsGroup: 1000
|
||||||
|
seccompProfile:
|
||||||
|
type: RuntimeDefault
|
||||||
|
containers:
|
||||||
|
- name: runner
|
||||||
|
image: gitea.dataprovider01.sandbox-cat-dat.simpl-europe.eu/j.r/distributed-execution:5122da4691f9
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
securityContext:
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
capabilities:
|
||||||
|
drop:
|
||||||
|
- ALL
|
||||||
|
env:
|
||||||
|
- name: DAGSTER_HOME
|
||||||
|
value: /dagster-home
|
||||||
|
command:
|
||||||
|
- sh
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
echo "===== T1: can this pod reach the metadata database? ====="
|
||||||
|
python -c "from distributed_execution.preflight import check_tcp_reachable; print(check_tcp_reachable('pg-cluster.common01.svc.cluster.local', 5432))"
|
||||||
|
echo "===== tightly_coupled_in_process_job ====="
|
||||||
|
dagster job execute -f src/distributed_execution/repository.py -j tightly_coupled_in_process_job
|
||||||
|
echo "===== T4: tightly_coupled_local_job ====="
|
||||||
|
dagster job execute -f src/distributed_execution/repository.py -j tightly_coupled_local_job
|
||||||
|
volumeMounts:
|
||||||
|
- name: dagster-home
|
||||||
|
mountPath: /dagster-home
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 200m
|
||||||
|
memory: 512Mi
|
||||||
|
limits:
|
||||||
|
cpu: "1"
|
||||||
|
memory: 1Gi
|
||||||
|
volumes:
|
||||||
|
- name: dagster-home
|
||||||
|
emptyDir: {}
|
||||||
60
yaml/sandbox/values-sandbox-gitea.yaml
Normal file
60
yaml/sandbox/values-sandbox-gitea.yaml
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
# Sandbox deployment values - Gitea registry.
|
||||||
|
#
|
||||||
|
# NOT CLUSTER-VERIFIED. The images and the registry behaviour here are confirmed
|
||||||
|
# - a probe pod ran from them on the sandbox on 2026-08-31 - but these values
|
||||||
|
# have never been applied as a code location. Registering this service against
|
||||||
|
# the sandbox Dagster is still blocked on the version skew below.
|
||||||
|
#
|
||||||
|
# VERSION SKEW, unresolved. These images carry dagster 1.13.19 (requirements.txt
|
||||||
|
# pins no upper bound, so the build took whatever was current). The sandbox
|
||||||
|
# control plane is 1.12.8. A code server is a gRPC server the webserver and
|
||||||
|
# daemon call into, so the two versions have to be compatible; a minor-version
|
||||||
|
# gap is not a supported configuration. Pin dagster to the control plane version
|
||||||
|
# and rebuild before reading a failure here as a bug in this service.
|
||||||
|
#
|
||||||
|
# Use these instead of the code.europa.eu references in
|
||||||
|
# yaml/values-dagster-distributed-execution.yaml and
|
||||||
|
# yaml/loosely-coupled/values-pipes-payload.yaml when deploying to the
|
||||||
|
# dataprovider01 sandbox. Both images were built and published by a Gitea Actions
|
||||||
|
# workflow held in the sandbox Gitea mirror of this repository, not here.
|
||||||
|
#
|
||||||
|
# The tag below is a short commit SHA and is the same for both images. That is
|
||||||
|
# the version lock: the code location and the payload it dispatches must come
|
||||||
|
# from one commit. Bump both together or not at all.
|
||||||
|
#
|
||||||
|
# The Gitea images are anonymously pullable, so NO pull secret is needed. A bare
|
||||||
|
# GET to the registry returns 401, which reads as a refusal but is only the start
|
||||||
|
# of the Docker token handshake; completing it anonymously and re-requesting the
|
||||||
|
# manifest returns 200 for both images. This was confirmed on 2026-08-31, and a
|
||||||
|
# probe pod carrying no credentials pulled and ran on the sandbox.
|
||||||
|
#
|
||||||
|
# An earlier revision of this file required a pull secret on both the deployment
|
||||||
|
# and the run launcher. That was wrong, and wrong in an expensive direction: it
|
||||||
|
# sent the reader looking for credentials that do not exist.
|
||||||
|
|
||||||
|
dagster:
|
||||||
|
dagster-user-deployments:
|
||||||
|
deployments:
|
||||||
|
- name: distributed-execution
|
||||||
|
image:
|
||||||
|
repository: gitea.dataprovider01.sandbox-cat-dat.simpl-europe.eu/j.r/distributed-execution
|
||||||
|
tag: 5122da4691f9
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
env:
|
||||||
|
- name: PIPES_PAYLOAD_IMAGE
|
||||||
|
value: gitea.dataprovider01.sandbox-cat-dat.simpl-europe.eu/j.r/distributed-execution-payload:5122da4691f9
|
||||||
|
# The sandbox release is named `dagster` but lives in dataprovider01;
|
||||||
|
# there is no namespace called `dagster` on that cluster.
|
||||||
|
- name: PIPES_PAYLOAD_NAMESPACE
|
||||||
|
value: dataprovider01
|
||||||
|
|
||||||
|
runLauncher:
|
||||||
|
config:
|
||||||
|
k8sRunLauncher:
|
||||||
|
runK8sConfig:
|
||||||
|
containerConfig:
|
||||||
|
env:
|
||||||
|
- name: PIPES_PAYLOAD_IMAGE
|
||||||
|
value: gitea.dataprovider01.sandbox-cat-dat.simpl-europe.eu/j.r/distributed-execution-payload:5122da4691f9
|
||||||
|
- name: PIPES_PAYLOAD_NAMESPACE
|
||||||
|
value: dataprovider01
|
||||||
@@ -13,8 +13,8 @@ dagster:
|
|||||||
config:
|
config:
|
||||||
k8sRunLauncher:
|
k8sRunLauncher:
|
||||||
# Namespace the run pods land in. Must be a namespace whose NetworkPolicy
|
# Namespace the run pods land in. Must be a namespace whose NetworkPolicy
|
||||||
# permits egress to Postgres, object storage and Vault - see AC1
|
# permits egress to Postgres, object storage and Vault - see the
|
||||||
# prerequisites in the user guide.
|
# prerequisites in section 2.3 of the user guide.
|
||||||
jobNamespace: dagster
|
jobNamespace: dagster
|
||||||
|
|
||||||
# Surfaces step failures as pod failures so kubectl and Dagster agree.
|
# Surfaces step failures as pod failures so kubectl and Dagster agree.
|
||||||
|
|||||||
@@ -28,7 +28,9 @@ dagster:
|
|||||||
|
|
||||||
image:
|
image:
|
||||||
pullPolicy: IfNotPresent
|
pullPolicy: IfNotPresent
|
||||||
repository: code.europa.eu:4567/simpl/simpl-open/data/supporting-data-services/distributed-execution
|
# $CI_REGISTRY_IMAGE for this project - the pipeline pushes here, so anything
|
||||||
|
# else is a reference to an image nobody builds.
|
||||||
|
repository: code.europa.eu:4567/simpl/simpl-open/data/supporting-data-services/distributed-execution/distributed-execution
|
||||||
tag: 0.0.0 # DO NOT CHANGE - replaced automatically by the pipeline before releasing
|
tag: 0.0.0 # DO NOT CHANGE - replaced automatically by the pipeline before releasing
|
||||||
|
|
||||||
port: 4000
|
port: 4000
|
||||||
|
|||||||
Reference in New Issue
Block a user