Skip to content
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

Add --local (-L) for --consistency-only and --predict-only options #485

Merged
merged 7 commits into from
Dec 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
- Adds a `--local` flag to `./batou deploy`, which can
be used in tandem with `--consistency-only` or `--predict-only` to
check and predict using the local host's state, without connecting to
the remote host.
7 changes: 6 additions & 1 deletion doc/source/cli/index.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ batou deploy

.. code-block:: console

usage: batou deploy [-h] [-p PLATFORM] [-t TIMEOUT] [-D] [-c] [-P] [-j JOBS]
usage: batou deploy [-h] [-p PLATFORM] [-t TIMEOUT] [-D] [-c] [-P]
[--local] [-j JOBS]
[--provision-rebuild]
environment

positional arguments:
Expand All @@ -50,6 +52,9 @@ batou deploy
Does not touch anything.
-P, --predict-only Only predict what updates would happen. Do not change
anything.
-L, --local When running in consistency-only or predict-only mode,
do not connect to the remote host, but check and
predict using the local host's state.
-j JOBS, --jobs JOBS Defines number of jobs running parallel to deploy. The
default results in a serial deployment of components.
Will override the environment settings for operational
Expand Down
Binary file not shown.
17 changes: 16 additions & 1 deletion src/batou/deploy.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,15 @@ def __init__(
dirty,
jobs,
predict_only=False,
check_and_predict_local=False,
provision_rebuild=False,
):
self.environment = Environment(
environment, timeout, platform, provision_rebuild=provision_rebuild
environment,
timeout,
platform,
provision_rebuild=provision_rebuild,
check_and_predict_local=check_and_predict_local,
)
self.environment.deployment = self

Expand Down Expand Up @@ -345,6 +350,7 @@ def main(
dirty,
consistency_only,
predict_only,
check_and_predict_local,
jobs,
provision_rebuild,
):
Expand All @@ -361,6 +367,14 @@ def main(
else:
ACTION = "DEPLOYMENT"
SUCCESS_FORMAT = {"green": True}
if check_and_predict_local:
if (not consistency_only) and (not predict_only):
output.error(
"The --local option is only to be used with --consistency-only or --predict-only."
)
sys.exit(1)
ACTION += " (local)"

with locked(".batou-lock", exit_on_failure=True):
deployment = Deployment(
environment,
Expand All @@ -369,6 +383,7 @@ def main(
dirty,
jobs,
predict_only,
check_and_predict_local,
provision_rebuild,
)
environment = deployment.environment
Expand Down
5 changes: 5 additions & 0 deletions src/batou/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ def __init__(
platform=None,
basedir=".",
provision_rebuild=False,
check_and_predict_local=False,
):
self.name: str = name
self.hosts: Dict[str, Host] = {}
Expand All @@ -140,6 +141,7 @@ def __init__(
self.timeout = timeout
self.platform = platform
self.provision_rebuild = provision_rebuild
self.check_and_predict_local = check_and_predict_local

self.hostname_mapping: Dict[str, str] = {}

Expand Down Expand Up @@ -291,6 +293,9 @@ def load_environment(self, config):

self._set_defaults()

if self.check_and_predict_local:
self.connect_method = "local"

if "vfs" in config:
sandbox = config["vfs"]["sandbox"]
sandbox = getattr(batou.vfs, sandbox)(self, config["vfs"])
Expand Down
9 changes: 9 additions & 0 deletions src/batou/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,15 @@ def main(args: Optional[list] = None) -> None:
help="Only predict what updates would happen. "
"Do not change anything.",
)
p.add_argument(
"-L",
"--local",
action="store_true",
dest="check_and_predict_local",
help="When running in consistency-only or predict-only mode, "
"do not connect to the remote host, but check and predict "
"using the local host's state.",
)
p.add_argument(
"-j",
"--jobs",
Expand Down
2 changes: 2 additions & 0 deletions src/batou/tests/test_deploy.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ def test_main_with_errors(capsys):
dirty=False,
consistency_only=False,
predict_only=False,
check_and_predict_local=False,
jobs=None,
provision_rebuild=False,
)
Expand Down Expand Up @@ -81,6 +82,7 @@ def test_main_fails_if_no_host_in_environment(capsys):
dirty=False,
consistency_only=False,
predict_only=False,
check_and_predict_local=False,
jobs=None,
provision_rebuild=False,
)
Expand Down
113 changes: 113 additions & 0 deletions src/batou/tests/test_endtoend.py
Original file line number Diff line number Diff line change
Expand Up @@ -372,3 +372,116 @@ def test_durations_are_shown_for_components():
============================= DEPLOYMENT FINISHED ==============================
"""
)


def test_check_consistency_works():
os.chdir("examples/tutorial-secrets")
out, _ = cmd("./batou deploy tutorial --consistency-only")
assert out == Ellipsis(
"""\
batou/2... (cpython 3...)
================================== Preparing ===================================
main: Loading environment `tutorial`...
main: Verifying repository ...
main: Loading secrets ...
================== Connecting hosts and configuring model ... ==================
localhost: Connecting via local (1/1)
=================================== Summary ====================================
Deployment took total=...s, connect=...s, deploy=NaN
========================== CONSISTENCY CHECK FINISHED ==========================
"""
)


def test_predicting_deployment_works():
os.chdir("examples/tutorial-secrets")
out, _ = cmd("./batou deploy tutorial --predict-only")
assert out == Ellipsis(
"""\
batou/2... (cpython 3...)
================================== Preparing ===================================
main: Loading environment `tutorial`...
main: Verifying repository ...
main: Loading secrets ...
================== Connecting hosts and configuring model ... ==================
localhost: Connecting via local (1/1)
======================== Predicting deployment actions =========================
localhost: Scheduling component hello ...
localhost > Hello > File('work/hello/hello') > Presence('hello')
localhost > Hello > File('work/hello/hello') > Content('hello')
Not showing diff as it contains sensitive data,
see .../examples/tutorial-secrets/work/.batou-diffs/...diff for the diff.
localhost > Hello > File('work/hello/other-secrets.yaml') > Presence('other-secrets.yaml')
localhost > Hello > File('work/hello/other-secrets.yaml') > Content('other-secrets.yaml')
Not showing diff as it contains sensitive data,
see .../examples/tutorial-secrets/work/.batou-diffs/...diff for the diff.
=================================== Summary ====================================
Deployment took total=...s, connect=...s, deploy=...s
======================== DEPLOYMENT PREDICTION FINISHED ========================
"""
)


def test_check_consistency_works_with_local():
os.chdir("examples/tutorial-secrets")
out, _ = cmd("./batou deploy gocept --consistency-only --local")
assert out == Ellipsis(
"""\
batou/2... (cpython 3...)
================================== Preparing ===================================
main: Loading environment `gocept`...
main: Verifying repository ...
main: Loading secrets ...
================== Connecting hosts and configuring model ... ==================
test01: Connecting via local (1/2)
test02: Connecting via local (2/2)
=================================== Summary ====================================
Deployment took total=...s, connect=...s, deploy=NaN
====================== CONSISTENCY CHECK (local) FINISHED ======================
"""
)


def test_predicting_deployment_works_with_local():
os.chdir("examples/tutorial-secrets")
out, _ = cmd("./batou deploy gocept --predict-only --local")
assert out == Ellipsis(
"""\
batou/2... (cpython 3...)
================================== Preparing ===================================
main: Loading environment `gocept`...
main: Verifying repository ...
main: Loading secrets ...
================== Connecting hosts and configuring model ... ==================
test01: Connecting via local (1/2)
test02: Connecting via local (2/2)
======================== Predicting deployment actions =========================
test01: Scheduling component hello ...
test02: Scheduling component hello ...
test01 > Hello > File('work/hello/hello') > Presence('hello')
test01 > Hello > File('work/hello/hello') > Content('hello')
hello ---
hello +++
hello @@ -0,0 +1,2 @@
hello +The magic word is None.
hello +The other word is None.
test01 > Hello > File('work/hello/other-secrets.yaml') > Presence('other-secrets.yaml')
test01 > Hello > File('work/hello/other-secrets.yaml') > Content('other-secrets.yaml')
Not showing diff as it contains sensitive data,
see .../batou/examples/tutorial-secrets/work/.batou-diffs/...diff for the diff.
test02 > Hello > File('work/hello/hello') > Presence('hello')
test02 > Hello > File('work/hello/hello') > Content('hello')
hello ---
hello +++
hello @@ -0,0 +1,2 @@
hello +The magic word is None.
hello +The other word is None.
test02 > Hello > File('work/hello/other-secrets.yaml') > Presence('other-secrets.yaml')
test02 > Hello > File('work/hello/other-secrets.yaml') > Content('other-secrets.yaml')
Not showing diff as it contains sensitive data,
see .../batou/examples/tutorial-secrets/work/.batou-diffs/...diff for the diff.
=================================== Summary ====================================
Deployment took total=...s, connect=...s, deploy=...s
==================== DEPLOYMENT PREDICTION (local) FINISHED ====================
"""
)
Loading