Repository navigation
Accept a command health check in the component schema (#161) - #170
Merged
Merged
Conversation
A component can declare healthCheck type: command (command argv, timeoutSeconds 1-300, attempts 1-20, no other key). The SDK parses it into value objects and the deploy, restart and rollback plans name the check and its command in wouldRun; the plan JSON gains no field (S-009-1, S-009-13). The engine does not run the check yet (#164), so the deploy role's entry points refuse a command check on their first task instead of passing an unrun gate. Fixes #161 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
shipmill-romamo Bot
added a commit
that referenced
this pull request
Oct 30, 2026
…11) (#171) * Accept a command health check in the component schema (#170) A component can declare healthCheck type: command (command argv, timeoutSeconds 1-300, attempts 1-20, no other key). The SDK parses it into value objects and the deploy, restart and rollback plans name the check and its command in wouldRun; the plan JSON gains no field (S-009-1, S-009-13). The engine does not run the check yet (#164), so the deploy role's entry points refuse a command check on their first task instead of passing an unrun gate. Fixes #161 Co-authored-by: shipmill-romamo[bot] <338557544+shipmill-romamo[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * Refuse a bad --source-schema with PRECONDITION and add migrate --data-schema (S-007-12, S-007-13) (#169) * Refuse a bad --source-schema with PRECONDITION and add migrate --data-schema A schema name must match ^[a-z_][a-z0-9_]*$ and be at most 63 characters, and may be named once; a malformed or repeated name now exits PRECONDITION from the command before any playbook, as spec 007 says, where it was a usage error and a repeat was silently dropped. cloudfall migrate takes --data-schema DATABASE=NAME beside --data, so the data step copies only the named schemas as data copy --source-schema does; one for a database with no --data is refused before any step (S-007-12, S-007-13). Fixes #126 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Describe a resumed migrate step by this run's options A pending step of a persisted plan kept the description it was saved with, so a data step saved with --data-schema crm=public and resumed without it reported "schema public" while it copied every schema (#126, S-007-13). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: shipmill-romamo[bot] <338557544+shipmill-romamo[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * Validate Domain routes (S-003-1, S-003-8..12) (#168) * Validate Domain routes (S-003-1, S-003-8..12) A Domain can now declare spec.routes: proxy routes (path + upstream) and static routes (path + static component, directory, spaFallback). The schema holds each route's shape and the release-relative directory and fallback; config validate checks the route source, path syntax, reserved and duplicate paths, and that a static component exists and is deployed on the proxy server. The inventory parses routes into value objects and serializes them only when present, so a Domain with only proxy.upstream is unchanged. Rendering routes comes with #162. Fixes #159 Part of #90 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Refuse a trailing newline in a static route's directory or spaFallback The releasePath schema pattern ends with $, which Python's re.search lets match before one trailing newline, so config validate accepted directory: "web\n" that ReleaseRelativePath then refused with a ValueError when the inventory loaded. Refuse control characters in the schema, as component.schema.json's controlCharacterFree does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: shipmill-romamo[bot] <338557544+shipmill-romamo[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * Refuse a data copy the target can't hold before dumping it A preflight on the target host, after the empty-target check and before pg_dump, reads the source and target catalogs and names every schema the source lacks, extension and policy role the target lacks, and auth. reference, taking every name only as a psql variable. Any finding refuses the copy with nothing dumped: data copy and migrate's data step exit PRECONDITION with data_copy_preflight_refused and the four lists, read whole from a findings file under --data-migrations. pg_dump takes the needed extensions with named schemas, and pg_restore runs in one transaction, so a failed restore leaves no table and no receipt. Spec 007 is built (S-007-6 to S-007-11). Fixes #125 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: shipmill-romamo[bot] <338557544+shipmill-romamo[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Plan
oneOfbranch,HealthCheckType.COMMANDand its value objects, the parser, the preview effects, the engine refusal; then the changelog fragmenttest_s009_1_*,test_s009_13_*)Summary
Adds the config contract of spec 009's command health check; the engine running it is #164.
config/schemas/v1/component.schema.json: a thirdhealthCheckoneOfbranch,type: commandwith a requiredcommand(non-empty list of non-empty strings, NUL refused asCommandArgvrefuses it),timeoutSeconds(1 to 300) andattempts(1 to 20),additionalProperties: false. Thehttpandnonebranches are unchangedsdk/src/cloudfall/domain.py:HealthCheckType.COMMAND, and the value objectsHealthCheckTimeout(1..300) andHealthCheckAttempts(1..20)sdk/src/cloudfall/inventory.py:ComponentCommandHealthCheck(CommandArgv,HealthCheckTimeout,HealthCheckAttempts), an optionalComponentHealthCheck.commandrequired exactly fortype: command, its parser andas_dict(so the rendered Ansible inventory carries it as declared)sdk/src/cloudfall/lifecycle.py:deploy,restartandrollbackwithout--yesadd "; its command health check<command>runs on each server after its restart" towouldRun. The plan JSON gains no fieldcloudfall_deployargument spec acceptstype: commandand itscommandkey;main.yml,restart.yml,rollback.ymlandhealth.ymlstart with a task that fails for a command check ("Component X declares a command health check, which this engine does not run yet (Gate a deploy on the command health check and receipt it (S-009-2..9, 11, 12) #164); nothing was changed"), so until Gate a deploy on the command health check and receipt it (S-009-2..9, 11, 12) #164 lands no deploy, restart or rollback of such a component passes an unrun gate.cloudfall healthreports itunhealthywith that message. Gate a deploy on the command health check and receipt it (S-009-2..9, 11, 12) #164 replaces these tasks with the check itselfTest plan
sdk/tests/test_command_health_check.py: S-009-1 (accepts, bounds, each malformed case exitsCONFIG_INVALID/schema_validation_failed, value objects, Q-3 shapes ofhttp/noneunchanged) and S-009-13 (the three plans exit 0, name the check and its command, run noansible-playbook, and carry the same keys as forhttp/none)engine/tests/test_ansible_inventory.py: a command check renders as declared;engine/tests/test_deploy_role.py: each entry point refuses a command check first and only a command check, and the argument spec accepts all three typesuv run ruff check .,uv run mypy,uv run cloudfall config validate --project config/examples,ansible-lint engine/ansible, and pytest on the touched and neighbouring files (test_command_health_check, test_validation, test_inventory, test_lifecycle, test_release_command_plan, test_ansible_inventory, test_deploy_role, test_release_command, test_deploy_templates, test_artifact_build_steps, test_catalog, test_ansible_reader): all green. The full suite is left to CIFixes #161
Part of #152
🤖 Generated with Claude Code