Skip to content

Commit

Permalink
Enable passing extra data via pyinfra.local.include (#1226)
Browse files Browse the repository at this point in the history
  • Loading branch information
TimothyWillard authored Nov 16, 2024
1 parent b110388 commit ffd6591
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 15 deletions.
31 changes: 31 additions & 0 deletions docs/using-operations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,37 @@ Including files can be used to break out operations across multiple files. Files
# Include & call all the operations in tasks/install_something.py
local.include("tasks/install_something.py")
Additional data can be passed across files via the ``data`` param to parameterize tasks and is available in ``host.data``. For example `tasks/create_user.py` could look like:

.. code:: python
from getpass import getpass
from pyinfra import host
from pyinfra.operations import server
group = host.data.get("group")
user = host.data.get("user")
server.group(
name=f"Ensure {group} is present",
group=group,
)
server.user(
name=f"Ensure {user} is present",
user=user,
group=group,
)
And and be called by other deploy scripts or tasks:

.. code:: python
from pyinfra import local
for group, user in (("admin", "Bob"), ("admin", "Joe")):
local.include("tasks/create_user.py", data={"group": group, "user": user})
See more in :doc:`examples: groups & roles <./examples/groups_roles>`.


Expand Down
5 changes: 3 additions & 2 deletions pyinfra/local.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from os import path
from typing import Optional

import click

Expand All @@ -10,7 +11,7 @@
from pyinfra.context import ctx_state


def include(filename: str):
def include(filename: str, data: Optional[dict] = None):
"""
Executes a local python file within the ``pyinfra.state.cwd``
directory.
Expand All @@ -33,7 +34,7 @@ def include(filename: str):

from pyinfra_cli.util import exec_file

with host.deploy(path.relpath(filename, state.cwd), None, None, in_deploy=False):
with host.deploy(path.relpath(filename, state.cwd), None, data, in_deploy=False):
exec_file(filename)

# One potential solution to the above is to add local as an actual
Expand Down
3 changes: 3 additions & 0 deletions tests/test_cli/deploy/deploy.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ def my_deploy():
# Include the whole file again, but for all hosts
local.include(path.join("tasks", "a_task.py"))

# Include a deploy file, with custom specified data
local.include(path.join("tasks", "b_task.py"), data={"keyword": "Important", "id": 1})

# Execute the @deploy function
my_deploy()

Expand Down
7 changes: 7 additions & 0 deletions tests/test_cli/deploy/tasks/b_task.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from pyinfra import host
from pyinfra.operations import server

server.shell(
name=f"{host.data.get('keyword')} task operation",
commands=f"echo {host.data.get('id')}",
)
28 changes: 15 additions & 13 deletions tests/test_cli/test_cli_deploy.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,26 +43,28 @@ def _assert_op_data(self, correct_op_name_and_host_names):
assert executed is False

def test_deploy(self):
task_file_path = path.join("tasks", "a_task.py")
a_task_file_path = path.join("tasks", "a_task.py")
b_task_file_path = path.join("tasks", "b_task.py")
nested_task_path = path.join("tasks", "another_task.py")
correct_op_name_and_host_names = [
("First main operation", True), # true for all hosts
("Second main operation", ("somehost",)),
("{0} | First task operation".format(task_file_path), ("anotherhost",)),
("{0} | Task order loop 1".format(task_file_path), ("anotherhost",)),
("{0} | 2nd Task order loop 1".format(task_file_path), ("anotherhost",)),
("{0} | Task order loop 2".format(task_file_path), ("anotherhost",)),
("{0} | 2nd Task order loop 2".format(task_file_path), ("anotherhost",)),
("{0} | First task operation".format(a_task_file_path), ("anotherhost",)),
("{0} | Task order loop 1".format(a_task_file_path), ("anotherhost",)),
("{0} | 2nd Task order loop 1".format(a_task_file_path), ("anotherhost",)),
("{0} | Task order loop 2".format(a_task_file_path), ("anotherhost",)),
("{0} | 2nd Task order loop 2".format(a_task_file_path), ("anotherhost",)),
(
"{0} | {1} | Second task operation".format(task_file_path, nested_task_path),
"{0} | {1} | Second task operation".format(a_task_file_path, nested_task_path),
("anotherhost",),
),
("{0} | First task operation".format(task_file_path), True),
("{0} | Task order loop 1".format(task_file_path), True),
("{0} | 2nd Task order loop 1".format(task_file_path), True),
("{0} | Task order loop 2".format(task_file_path), True),
("{0} | 2nd Task order loop 2".format(task_file_path), True),
("{0} | {1} | Second task operation".format(task_file_path, nested_task_path), True),
("{0} | First task operation".format(a_task_file_path), True),
("{0} | Task order loop 1".format(a_task_file_path), True),
("{0} | 2nd Task order loop 1".format(a_task_file_path), True),
("{0} | Task order loop 2".format(a_task_file_path), True),
("{0} | 2nd Task order loop 2".format(a_task_file_path), True),
("{0} | {1} | Second task operation".format(a_task_file_path, nested_task_path), True),
("{0} | Important task operation".format(b_task_file_path), True),
("My deploy | First deploy operation", True),
("My deploy | My nested deploy | First nested deploy operation", True),
("My deploy | Second deploy operation", True),
Expand Down

0 comments on commit ffd6591

Please sign in to comment.