mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 10:59:59 +00:00
perf(constructor): carry the applications SPOT into the bootstrap roles
The constructor parked no applications carrier between the merge block and the token store, so every lookup in the svc-swarm-node, svc-storage, svc-registry and svc-virt bootstrap rendered the SPOT cold, 25 to 30 s each on a loaded host. A carrier there was unsafe: in swarm, svc-storage-nfs-server mounts the NFS export over the controller's DIR_VAR_LIB, so the tokens file the render reads can appear in the middle of that section, and the cache key did not notice. merged_applications_cache_key now includes the tokens file's path, mtime and size, as the users cache key already did, so a carrier rejects itself once the tokens change. A carrier parked after the add_host tasks then serves the bootstrap roles. It is parked only in swarm mode: in compose the section runs in about a second, so a carrier there would add a render without saving one. In a swarm drill of web-app-prometheus up to the known NFS probe-write failure, "Resolve the NFS server backend flavor" went from 29.6 s to 0.07 s, "Probe-mount the NFS export" from 26.4 s to 0.4 s, "Mount cluster-shared infinito state on controller" from 23.7 s to 0.5 s and "Ensure Docker-In-Docker DNS works" from 30.0 s to 3.6 s; the run to that point took 768 s instead of 1735 s. Closes #925 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
2e710b35f7
commit
778c18fb23
4 files changed
+42
-12
No files matched your search
@@ -10,14 +10,12 @@ instead of rendering::
|
||||
- name: 🧊 Render the applications SPOT once and carry it into every task's worker
|
||||
applications_carrier: {}
|
||||
|
||||
``tasks/stages/01_constructor.yml`` parks two of them. The stage-wide one
|
||||
sits after the token store so the embedded user records already carry the
|
||||
loaded tokens, and after the ``add_host`` tasks because 114 roles gate
|
||||
services on ``group_names`` and the payload bakes those in. The
|
||||
merge block opens an earlier, block-scoped one and drops it again at the
|
||||
block's end, because ``merged_applications_cache_key`` reads neither
|
||||
``group_names`` nor the token file: a carrier left standing across either
|
||||
would be served unchanged where a fresh render belongs::
|
||||
``tasks/stages/01_constructor.yml`` parks three of them: a block-scoped one
|
||||
for the merge block, which it drops again at the block's end, one after the
|
||||
``add_host`` tasks for the swarm bootstrap roles, parked only when
|
||||
``DEPLOYMENT_MODE`` is ``swarm``, and the stage-wide one after the token store. ``merged_applications_cache_key`` reads ``group_names`` and the
|
||||
tokens file's path, mtime and size, so a carrier whose groups or tokens no
|
||||
longer match is rejected and the reader renders afresh::
|
||||
|
||||
- name: 🧊 Drop the merge-block carrier so later stages re-render
|
||||
applications_carrier:
|
||||
|
||||
@@ -161,6 +161,10 @@
|
||||
run_once: true
|
||||
changed_when: false
|
||||
|
||||
- name: 🧊 Render the applications SPOT once for the bootstrap section
|
||||
applications_carrier: {}
|
||||
when: DEPLOYMENT_MODE == 'swarm'
|
||||
|
||||
- name: "🥾 Bootstrap svc-swarm-node"
|
||||
ansible.builtin.include_role:
|
||||
name: svc-swarm-node
|
||||
|
||||
@@ -389,6 +389,24 @@ class TestGetMergedApplicationsCarrierFact(unittest.TestCase):
|
||||
merged["web-app-foo"]["services"]["foo"]["image"], "override"
|
||||
)
|
||||
|
||||
def test_a_changed_tokens_file_rejects_the_carrier(self):
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
roles = _seed_minimal_roles(Path(tmp))
|
||||
tokens = Path(tmp) / "tokens.yml"
|
||||
tokens.write_text("{}\n", encoding="utf-8")
|
||||
variables = self._variables()
|
||||
variables["FILE_TOKENS"] = str(tokens)
|
||||
key = merged_applications_cache_key(variables, roles_dir=roles)
|
||||
variables[APPLICATIONS_RENDERED_FACT] = {
|
||||
"key": [key[0], list(key[1])],
|
||||
"applications": {"web-app-foo": {"carried": True}},
|
||||
}
|
||||
tokens.write_text("users: {}\n", encoding="utf-8")
|
||||
merged = cache_apps.get_merged_applications(
|
||||
variables=variables, roles_dir=roles, templar=None
|
||||
)
|
||||
self.assertNotIn("carried", merged["web-app-foo"])
|
||||
|
||||
def test_malformed_carrier_is_ignored(self):
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
roles = _seed_minimal_roles(Path(tmp))
|
||||
|
||||
Vendored
+14
-4
@@ -13,7 +13,12 @@ from __future__ import annotations
|
||||
from collections.abc import Mapping
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from .base import _cache_key, _resolve_roles_dir, _stable_variables_signature
|
||||
from .base import (
|
||||
_cache_key,
|
||||
_resolve_roles_dir,
|
||||
_stable_variables_signature,
|
||||
_tokens_file_signature,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import os
|
||||
@@ -30,16 +35,21 @@ def merged_applications_cache_key(
|
||||
|
||||
Args:
|
||||
variables: The play's variable scope. Only the subset that
|
||||
`_stable_variables_signature` reads influences the key.
|
||||
`_stable_variables_signature` reads, and the tokens file it
|
||||
resolves to, influence the key.
|
||||
roles_dir: Roles tree the payload is built from; defaults to the
|
||||
repository's `roles/`.
|
||||
|
||||
Returns:
|
||||
``(resolved roles dir, stable variables signature)``.
|
||||
``(resolved roles dir, stable variables signature extended by the
|
||||
tokens file's path, mtime and size)``.
|
||||
"""
|
||||
from .users import _resolve_tokens_file
|
||||
|
||||
tokens = _tokens_file_signature(_resolve_tokens_file(variables))
|
||||
return (
|
||||
_cache_key(_resolve_roles_dir(roles_dir=roles_dir)),
|
||||
_stable_variables_signature(variables),
|
||||
(*_stable_variables_signature(variables), *(str(part) for part in tokens)),
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user