Repository navigation
Node tags, and --tag on the fleet commands #84
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -602,15 +602,18 @@ def _across_the_fleet( | |
| what: str, | ||
| *, | ||
| rollback: int | None = None, | ||
| tag: str | None = None, | ||
| as_json: bool, | ||
| ) -> None: | ||
| """One line per node, whichever way each of them went.""" | ||
| if what == "apply": | ||
| found = _asking(url, token, lambda client: client.firewall_apply_fleet(rollback=rollback)) | ||
| found = _asking( | ||
| url, token, lambda client: client.firewall_apply_fleet(rollback=rollback, tag=tag) | ||
| ) | ||
| elif what == "confirm": | ||
| found = _asking(url, token, lambda client: client.firewall_confirm_fleet()) | ||
| found = _asking(url, token, lambda client: client.firewall_confirm_fleet(tag=tag)) | ||
| else: | ||
| found = _asking(url, token, lambda client: client.firewall_restore_fleet()) | ||
| found = _asking(url, token, lambda client: client.firewall_restore_fleet(tag=tag)) | ||
|
|
||
| if as_json: | ||
| _dump(found.model_dump(mode="json")) | ||
|
|
@@ -653,6 +656,9 @@ def firewall_apply( | |
| fleet: Annotated[ | ||
| bool, typer.Option("--fleet", help="Every warden in the fleet, each on its own.") | ||
| ] = False, | ||
| tagged: Annotated[ | ||
| str | None, typer.Option("--tag", help="Only the nodes carrying this tag.") | ||
| ] = None, | ||
|
Comment on lines
+659
to
+661
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win Reject
🤖 Prompt for AI Agents |
||
| at: Annotated[ | ||
| str | None, typer.Option("--node", help="One node in the fleet, through the hub.") | ||
| ] = None, | ||
|
|
@@ -670,7 +676,7 @@ def firewall_apply( | |
| at once. `--node build-01` asks exactly one. | ||
| """ | ||
| if fleet: | ||
| _across_the_fleet(url, token, "apply", rollback=rollback, as_json=as_json) | ||
| _across_the_fleet(url, token, "apply", rollback=rollback, tag=tagged, as_json=as_json) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win Include the selected tag in the confirmation command. When 🤖 Prompt for AI Agents |
||
| return | ||
| if at: | ||
| said = _asking(url, token, lambda client: client.firewall_apply_on(at, rollback=rollback)) | ||
|
|
@@ -863,6 +869,9 @@ def firewall_confirm( | |
| fleet: Annotated[ | ||
| bool, typer.Option("--fleet", help="Every warden in the fleet, each on its own.") | ||
| ] = False, | ||
| tagged: Annotated[ | ||
| str | None, typer.Option("--tag", help="Only the nodes carrying this tag.") | ||
| ] = None, | ||
| at: Annotated[ | ||
| str | None, typer.Option("--node", help="One node in the fleet, through the hub.") | ||
| ] = None, | ||
|
|
@@ -876,7 +885,7 @@ def firewall_confirm( | |
| back when its own window runs out. | ||
| """ | ||
| if fleet: | ||
| _across_the_fleet(url, token, "confirm", as_json=as_json) | ||
| _across_the_fleet(url, token, "confirm", tag=tagged, as_json=as_json) | ||
| return | ||
| if at: | ||
| said = _asking(url, token, lambda client: client.firewall_confirm_on(at)) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -326,6 +326,11 @@ class Settings(BaseSettings): | |
| upstream: str | None = None | ||
| cluster_token: str | None = None | ||
| node_ttl: int = Field(default=90, ge=10, le=86_400) | ||
| # `web`, `eu-west`, `db` - what this machine is, travelling in the | ||
| # announcement it already sends. On the node rather than in a list on the | ||
| # hub: two places that know what a machine is disagree the first time one | ||
| # is rebuilt, and the machine is the one that knows. | ||
| tags: WordSet = Field(default_factory=set) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win 🔎 Supported by static analysis🏁 Script executed: #!/bin/bash
set -euo pipefail
python -m pip install --quiet "pydantic==2.9.0" "pydantic-settings==2.6.0"
python - <<'PY'
from typing import Annotated
from pydantic import BaseModel, Field, StringConstraints
from pydantic.functional_validators import BeforeValidator
from pydantic_settings import BaseSettings
def parse_words(value: object) -> object:
return {word.strip() for word in value.split(",") if word.strip()} if isinstance(value, str) else value
WordSet = Annotated[set[str], BeforeValidator(parse_words)]
Tag = Annotated[str, StringConstraints(pattern=r"^[a-z0-9][a-z0-9._-]{0,31}$", strip_whitespace=True)]
class Settings(BaseSettings):
tags: WordSet = Field(default_factory=set)
class Announcement(BaseModel):
tags: list[Tag]
tags = Settings(tags="Web Servers").tags
print(tags)
try:
Announcement(tags=sorted(tags))
except Exception as exc:
print(type(exc).__name__, exc)
PYRepository: vxnsin/warden Length of output: 188 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- target file symbols and imports ---'
rg -n -C 8 'WordSet|Tag|class Settings|class NodeAnnouncement|tags:' src/warden/core/config.py
printf '%s\n' '--- direct references to Settings.tags and NodeAnnouncement ---'
rg -n -C 4 'NodeAnnouncement|Settings\(|\.tags\b|tags=' src tests 2>/dev/null | head -n 240Repository: vxnsin/warden Length of output: 16829 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- config imports and tag-related definitions ---'
sed -n '1,90p' src/warden/core/config.py
sed -n '255,345p' src/warden/core/config.py
printf '%s\n' '--- announcement model ---'
sed -n '145,195p' src/warden/models.py
printf '%s\n' '--- announcement construction and submission ---'
sed -n '1,70p' src/warden/fleet/upstream.py
rg -n -C 8 'announcement\(|announce\(|NodeAnnouncement\(' src/wardenRepository: vxnsin/warden Length of output: 32099 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- resolved Tag declaration and model imports ---'
sed -n '1,80p' src/warden/models.py
rg -n -C 5 'Tag\s*=|StringConstraints|pattern=|NodeAnnouncement' src/warden/models.py src/warden/core/config.py tests 2>/dev/null | head -n 180
printf '%s\n' '--- upstream lifecycle and error handling ---'
sed -n '70,150p' src/warden/fleet/upstream.pyRepository: vxnsin/warden Length of output: 10345 Validate
🤖 Prompt for AI Agents |
||
| require_https: bool = False | ||
|
|
||
| @classmethod | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Expose tagged fleet restore in
firewall_restorefirewall_restoreaccepts onlysnapshotand always calls localguard.roll_back; it has no--fleetor--tagpath to_across_the_fleet. Therefore, users cannot select tagged nodes withwarden firewall restore. Add the fleet and tag options, route the fleet branch through_across_the_fleet(..., "restore", tag=tagged, ...), and preserve the existing local snapshot path.🤖 Prompt for AI Agents