mirror of
https://scm.tikali.ai/tikali/applications/monky/monky-deployd.git
synced 2026-09-18 08:56:16 +00:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b39a60af46 | |||
| fcf2dcb1eb | |||
| 31586c3058 |
@@ -1,6 +1,18 @@
|
|||||||
<!-- xlate:verbatim-fences -->
|
<!-- xlate:verbatim-fences -->
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 0.1.5 — 2026-09-07
|
||||||
|
|
||||||
|
- **`${VAR}` inside comment lines is not a reference.** The renderer's `.env.template` header literally says
|
||||||
|
"substitutes every ${VAR}", which the refusal check counted as an unresolved variable
|
||||||
|
(`ENV_INCOMPLETE: unresolved: VAR`) — the first bundle on env-qa-02 was refused for it.
|
||||||
|
|
||||||
|
- **config: `tenancy.port` is the service's intercept port (443), not the in-pod 8081.** With 8081 the SDK
|
||||||
|
found no intercept and the dial failed (`service not available`, then a bare `TypeError` from the SDK's
|
||||||
|
fallback). `install.sh` now writes 443; `config.example.yaml` updated.
|
||||||
|
- **transport sdk: clear error instead of a TypeError** when an address has no intercept or the identity
|
||||||
|
has no dial policy for the service (`TransportError` names the host:port and what to check).
|
||||||
|
|
||||||
## 0.1.4 — 2026-09-07
|
## 0.1.4 — 2026-09-07
|
||||||
|
|
||||||
- **install.sh: `ziti-edge-tunnel.service` failed to start after enrolment** (`203/EXEC`: the package's
|
- **install.sh: `ziti-edge-tunnel.service` failed to start after enrolment** (`203/EXEC`: the package's
|
||||||
|
|||||||
@@ -23,9 +23,9 @@ you the enrolment JWT, a one-time **bootstrap deploy grant** and the read-only *
|
|||||||
|
|
||||||
```sh
|
```sh
|
||||||
T=<deploy token> # read-only GitLab deploy token (read_package_registry); the kit carries it
|
T=<deploy token> # read-only GitLab deploy token (read_package_registry); the kit carries it
|
||||||
curl -sSf -H "DEPLOY-TOKEN: $T" https://scm.tikali.ai/api/v4/projects/69/packages/generic/monky-deployd/0.1.4/install.sh \
|
curl -sSf -H "DEPLOY-TOKEN: $T" https://scm.tikali.ai/api/v4/projects/69/packages/generic/monky-deployd/0.1.5/install.sh \
|
||||||
| sudo bash -s -- --env env-qa-02 --site cbs --token "$T" --bootstrap-file bootstrap.jwt --enrol-jwt ./monky-host.env-qa-02.jwt
|
| sudo bash -s -- --env env-qa-02 --site cbs --token "$T" --bootstrap-file bootstrap.jwt --enrol-jwt ./monky-host.env-qa-02.jwt
|
||||||
# [--transport sdk|proxy|system] [--version 0.1.4] [--docker-data-root /home/docker-data] [--laptop] [--bao-ca openbao-ca.pem] [--source gitlab|gitea]
|
# [--transport sdk|proxy|system] [--version 0.1.5] [--docker-data-root /home/docker-data] [--laptop] [--bao-ca openbao-ca.pem] [--source gitlab|gitea]
|
||||||
```
|
```
|
||||||
|
|
||||||
`install.sh` installs `ziti-edge-tunnel` (OpenZiti `jammy` suite) and `docker-compose-plugin` if
|
`install.sh` installs `ziti-edge-tunnel` (OpenZiti `jammy` suite) and `docker-compose-plugin` if
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ template → optional openbao-ca PEM → optional `monky-deployd-proxy.service`
|
|||||||
|
|
||||||
| var | note |
|
| var | note |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `monky_deployd_version` | pinned release, e.g. `0.1.4` |
|
| `monky_deployd_version` | pinned release, e.g. `0.1.5` |
|
||||||
| `monky_deployd_download_token` | **vaulted**: GitLab deploy token, scope `read_package_registry` only (revocable) — the registry is private; seeded in OpenBao at `monky/monky-tenancy/deployd-download` key `token` (path/key are the operator's choice). Empty = no header (only works with the Gitea `base_url`) |
|
| `monky_deployd_download_token` | **vaulted**: GitLab deploy token, scope `read_package_registry` only (revocable) — the registry is private; seeded in OpenBao at `monky/monky-tenancy/deployd-download` key `token` (path/key are the operator's choice). Empty = no header (only works with the Gitea `base_url`) |
|
||||||
| `monky_deployd_env_id` / `_site` / `_transport` | per host (`env-dev-06`, `cbs`, `sdk`) |
|
| `monky_deployd_env_id` / `_site` / `_transport` | per host (`env-dev-06`, `cbs`, `sdk`) |
|
||||||
| `monky_deployd_bootstrap_grant` | tenancy-minted deploy grant (1 h) — `ansible-vault` or a lookup at play time; empty keeps the existing token |
|
| `monky_deployd_bootstrap_grant` | tenancy-minted deploy grant (1 h) — `ansible-vault` or a lookup at play time; empty keeps the existing token |
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
# monky_deployd — install and configure the Monky backend pull agent (MONKY-ADR-0028 §D).
|
# monky_deployd — install and configure the Monky backend pull agent (MONKY-ADR-0028 §D).
|
||||||
# Copy this role into osg1-07 (roles/monky_deployd) and roll to env-dev-06..09 after the pilot.
|
# Copy this role into osg1-07 (roles/monky_deployd) and roll to env-dev-06..09 after the pilot.
|
||||||
monky_deployd_version: "0.1.4"
|
monky_deployd_version: "0.1.5"
|
||||||
monky_deployd_deb: "monky-deployd_{{ monky_deployd_version }}_amd64.deb"
|
monky_deployd_deb: "monky-deployd_{{ monky_deployd_version }}_amd64.deb"
|
||||||
# PRIMARY download = the GitLab project's generic package registry on scm.tikali.ai. Inside the estate
|
# PRIMARY download = the GitLab project's generic package registry on scm.tikali.ai. Inside the estate
|
||||||
# gitea.cbs.tikali.net is split-horizon to jump1's RED EIP (10.10.0.175, no HTTP ingress), so backend
|
# gitea.cbs.tikali.net is split-horizon to jump1's RED EIP (10.10.0.175, no HTTP ingress), so backend
|
||||||
|
|||||||
+2
-2
@@ -1,4 +1,4 @@
|
|||||||
# /etc/monky-deployd/config.yaml — monky-deployd v0.1.4 (MONKY-ADR-0028 §D)
|
# /etc/monky-deployd/config.yaml — monky-deployd v0.1.5 (MONKY-ADR-0028 §D)
|
||||||
# Written by packaging/install.sh (or the ansible role monky_deployd). YAML *subset*: maps, scalars,
|
# Written by packaging/install.sh (or the ansible role monky_deployd). YAML *subset*: maps, scalars,
|
||||||
# simple lists, comments. Keys not listed here are a config error.
|
# simple lists, comments. Keys not listed here are a config error.
|
||||||
|
|
||||||
@@ -10,7 +10,7 @@ identity: /opt/openziti/etc/identities/monky-host.env-qa-02.json # the box's h
|
|||||||
tenancy:
|
tenancy:
|
||||||
service: monky.tenancy.deploy # ziti service bound by the tenancy sidecar -> 127.0.0.1:8081 (agent entrypoint)
|
service: monky.tenancy.deploy # ziti service bound by the tenancy sidecar -> 127.0.0.1:8081 (agent entrypoint)
|
||||||
host: monky.tenancy.deploy # intercept host (sdk/system); defaults to `service`
|
host: monky.tenancy.deploy # intercept host (sdk/system); defaults to `service`
|
||||||
port: 8081
|
port: 443 # intercept port of monky.tenancy.deploy (in-pod 8081)
|
||||||
scheme: http # plain HTTP inside the mesh; the mesh is the transport security
|
scheme: http # plain HTTP inside the mesh; the mesh is the transport security
|
||||||
proxy_addr: 127.0.0.1:18443 # transport: proxy
|
proxy_addr: 127.0.0.1:18443 # transport: proxy
|
||||||
timeout_s: 30
|
timeout_s: 30
|
||||||
|
|||||||
@@ -4,4 +4,4 @@ Dials monky-tenancy over the mesh with the box's host identity, fetches the rend
|
|||||||
leases a deploy grant, logs in to OpenBao, reads its own secrets, runs `docker compose`,
|
leases a deploy grant, logs in to OpenBao, reads its own secrets, runs `docker compose`,
|
||||||
reports. Stdlib only; the optional `openziti` SDK is the `sdk` transport."""
|
reports. Stdlib only; the optional `openziti` SDK is the `sdk` transport."""
|
||||||
|
|
||||||
__version__ = "0.1.4"
|
__version__ = "0.1.5"
|
||||||
|
|||||||
@@ -144,12 +144,18 @@ def parse(data: bytes, *, max_bytes: int = 4 * 1024 * 1024) -> Bundle:
|
|||||||
# --- refusal checks (pure; names only, never values) -----------------------------------------
|
# --- refusal checks (pure; names only, never values) -----------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
def _code_lines(text: str) -> str:
|
||||||
|
"""Drop comment lines: a `# … ${VAR} …` remark in .env.template (the renderer writes one)
|
||||||
|
is not a reference. Compose/dotenv comments start with `#` after optional whitespace."""
|
||||||
|
return "\n".join(ln for ln in text.splitlines() if not ln.lstrip().startswith("#"))
|
||||||
|
|
||||||
|
|
||||||
def referenced_vars(text: str) -> set[str]:
|
def referenced_vars(text: str) -> set[str]:
|
||||||
return {m.group(1) for m in _VAR_RE.finditer(text)}
|
return {m.group(1) for m in _VAR_RE.finditer(_code_lines(text))}
|
||||||
|
|
||||||
|
|
||||||
def defaulted_vars(text: str) -> set[str]:
|
def defaulted_vars(text: str) -> set[str]:
|
||||||
return {m.group(1) for m in _VAR_DEFAULTED_RE.finditer(text)}
|
return {m.group(1) for m in _VAR_DEFAULTED_RE.finditer(_code_lines(text))}
|
||||||
|
|
||||||
|
|
||||||
def unresolved_vars(bundle: Bundle, provided: set[str]) -> list[str]:
|
def unresolved_vars(bundle: Bundle, provided: set[str]) -> list[str]:
|
||||||
|
|||||||
@@ -104,6 +104,14 @@ class SdkTransport(Transport):
|
|||||||
return socket.create_connection((host, port), timeout=timeout)
|
return socket.create_connection((host, port), timeout=timeout)
|
||||||
except OSError as exc:
|
except OSError as exc:
|
||||||
raise TransportError(f"transport sdk: dial {host}:{port} failed: {exc}") from exc
|
raise TransportError(f"transport sdk: dial {host}:{port} failed: {exc}") from exc
|
||||||
|
except Exception as exc: # noqa: BLE001 - the SDK raises bare Exception((code, msg)) and TypeError
|
||||||
|
# openziti-sdk-py: an address with NO matching intercept falls through to
|
||||||
|
# PySocket.connect(tuple) → TypeError; a matching intercept the identity may not dial
|
||||||
|
# raises Exception((-18, 'service not available')) — env-qa-02 pilot, 2026-09-07.
|
||||||
|
raise TransportError(
|
||||||
|
f"transport sdk: dial {host}:{port} failed: {exc} — no intercept for that host:port, or this "
|
||||||
|
"identity has no dial policy for the service (check the intercept port and the identity's attrs)"
|
||||||
|
) from exc
|
||||||
|
|
||||||
def describe(self) -> str:
|
def describe(self) -> str:
|
||||||
return f"sdk(identity={self.identity_path})"
|
return f"sdk(identity={self.identity_path})"
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
#
|
#
|
||||||
# T=<read-only GitLab deploy token, scope read_package_registry> # from the install kit / OpenBao
|
# T=<read-only GitLab deploy token, scope read_package_registry> # from the install kit / OpenBao
|
||||||
# curl -sSf -H "DEPLOY-TOKEN: $T" \
|
# curl -sSf -H "DEPLOY-TOKEN: $T" \
|
||||||
# https://scm.tikali.ai/api/v4/projects/69/packages/generic/monky-deployd/0.1.4/install.sh \
|
# https://scm.tikali.ai/api/v4/projects/69/packages/generic/monky-deployd/0.1.5/install.sh \
|
||||||
# | sudo bash -s -- --env env-qa-02 --site cbs --token "$T" --bootstrap-file bootstrap.jwt \
|
# | sudo bash -s -- --env env-qa-02 --site cbs --token "$T" --bootstrap-file bootstrap.jwt \
|
||||||
# [--transport sdk|proxy|system] [--version 0.1.4] [--enrol-jwt /path/monky-host.env-qa-02.jwt] \
|
# [--transport sdk|proxy|system] [--version 0.1.5] [--enrol-jwt /path/monky-host.env-qa-02.jwt] \
|
||||||
# [--laptop] [--source gitlab|gitea] [--docker-data-root /home/docker-data]
|
# [--laptop] [--source gitlab|gitea] [--docker-data-root /home/docker-data]
|
||||||
#
|
#
|
||||||
# --token / MONKY_DEPLOYD_TOKEN: the GitLab project is PRIVATE (its parent groups are private, so it
|
# --token / MONKY_DEPLOYD_TOKEN: the GitLab project is PRIVATE (its parent groups are private, so it
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
umask 077
|
umask 077
|
||||||
|
|
||||||
DEFAULT_VERSION="0.1.4"
|
DEFAULT_VERSION="0.1.5"
|
||||||
# Download source. PRIMARY is the GitLab project's generic package registry on scm.tikali.ai: inside
|
# Download source. PRIMARY is the GitLab project's generic package registry on scm.tikali.ai: inside
|
||||||
# the estate gitea.cbs.tikali.net is split-horizon to jump1's RED EIP (10.10.0.175), which has no HTTP
|
# the estate gitea.cbs.tikali.net is split-horizon to jump1's RED EIP (10.10.0.175), which has no HTTP
|
||||||
# ingress, so backend boxes cannot reach the Gitea mirror (cbs/iac#102); scm.tikali.ai they can. The
|
# ingress, so backend boxes cannot reach the Gitea mirror (cbs/iac#102); scm.tikali.ai they can. The
|
||||||
@@ -233,7 +233,7 @@ identity: $IDENTITY
|
|||||||
tenancy:
|
tenancy:
|
||||||
service: monky.tenancy.deploy
|
service: monky.tenancy.deploy
|
||||||
host: monky.tenancy.deploy
|
host: monky.tenancy.deploy
|
||||||
port: 8081
|
port: 443 # the service's INTERCEPT port (host.v1 forwards to 8081 inside the pod); plain HTTP inside the mesh
|
||||||
scheme: http
|
scheme: http
|
||||||
proxy_addr: 127.0.0.1:18443
|
proxy_addr: 127.0.0.1:18443
|
||||||
bao:
|
bao:
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "monky-deployd"
|
name = "monky-deployd"
|
||||||
version = "0.1.4"
|
version = "0.1.5"
|
||||||
description = "Monky backend pull agent: checkin -> bundle -> lease -> OpenBao -> docker compose -> report, over the ziti mesh (MONKY-ADR-0028)"
|
description = "Monky backend pull agent: checkin -> bundle -> lease -> OpenBao -> docker compose -> report, over the ziti mesh (MONKY-ADR-0028)"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.12"
|
requires-python = ">=3.12"
|
||||||
|
|||||||
@@ -79,3 +79,16 @@ def test_disk_need_bytes_spellings():
|
|||||||
assert b.parse(tar_bytes(make_files(meta={"agent": {"disk_need_bytes": 5}}))).disk_need_bytes == 5
|
assert b.parse(tar_bytes(make_files(meta={"agent": {"disk_need_bytes": 5}}))).disk_need_bytes == 5
|
||||||
assert b.parse(tar_bytes(make_files(meta={"disk": {"need_bytes": 7}}))).disk_need_bytes == 7
|
assert b.parse(tar_bytes(make_files(meta={"disk": {"need_bytes": 7}}))).disk_need_bytes == 7
|
||||||
assert b.parse(tar_bytes(make_files())).disk_need_bytes == 0
|
assert b.parse(tar_bytes(make_files())).disk_need_bytes == 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_placeholders_in_comment_lines_are_not_references():
|
||||||
|
"""The renderer's .env.template header says '... substitutes every ${VAR} ...' — that must not
|
||||||
|
become an unresolved 'VAR' (env-qa-02 pilot: ENV_INCOMPLETE: unresolved: VAR)."""
|
||||||
|
from monky_deployd.bundle import defaulted_vars, referenced_vars
|
||||||
|
|
||||||
|
text = (
|
||||||
|
"# The on-box agent substitutes every ${VAR} from OpenBao per secrets.manifest.json.\n"
|
||||||
|
" # ${ALSO_COMMENT}\nGEMINI_API_KEY=${GEMINI_API_KEY}\nPG=${PGPASSWORD:-x}\n"
|
||||||
|
)
|
||||||
|
assert referenced_vars(text) == {"GEMINI_API_KEY", "PGPASSWORD"}
|
||||||
|
assert defaulted_vars(text) == {"PGPASSWORD"}
|
||||||
|
|||||||
Reference in New Issue
Block a user