Skip to content

Commit

Permalink
Merge pull request #485 from flyingcircusio/add-check-and-predict-loc…
Browse files Browse the repository at this point in the history
…al-flag

Add `--local` (`-L`) for `--consistency-only` and `--predict-only` options
  • Loading branch information
zagy authored Dec 2, 2024
2 parents 4b0e322 + f4cbefb commit 5cad7bd
Show file tree
Hide file tree
Showing 8 changed files with 155 additions and 2 deletions.
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 ====================
"""
)

0 comments on commit 5cad7bd

Please sign in to comment.