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

Pass User Specified Data Via pyinfra.local.include #1173

Open
TimothyWillard opened this issue Aug 11, 2024 · 1 comment
Open

Pass User Specified Data Via pyinfra.local.include #1173

TimothyWillard opened this issue Aug 11, 2024 · 1 comment
Labels
CLI CLI mode specific issues.

Comments

@TimothyWillard
Copy link

Is your feature request related to a problem? Please describe

When using pyinfra I generally write two kinds of scripts:

  1. Small and modular deployments that can do specific operations, and
  2. Larger more complete deployments that are composed of multiple scripts from (1) using pyinfra.local.include.

When running the scripts from (1) I'll often get prompted multiple times for the same credentials for decrypting secrets needed in the process of deployment by the scripts from (1) using getpass.getpass or similar. A more concrete example would be a script that deploys a web app which is made of three smaller modules:

  1. A script to create database users and provision grants to those users needs a password to decrypt the database's root user password,
  2. A script to restart the web app's systemd service and provision database credentials which need a password to decrypt those credentials, and
  3. A script to write the config for and restart a caddy webserver to proxy the web app.

A larger script would execute (1), (2), and (3) in order and prompt for the same password twice in (1) and (2).

Describe the solution you'd like

My solution to this would be extending pyinfra.local.include's API to be:

def include(filename: str, data: None | dict[str, Any] = None):
  pass

Where the data parameter (or whatever a better name would be) would contain variables that could be passed to the script being executed. There is already some data being passed to the executed script in pyinfra_cli.util.exec_file, could just pass the user provided data along in a __pyinfra__ attribute (in pyinfra_cli/util.py):

    # Create some base attributes for our "module"
    data = {"__file__": filename, "__pyinfra__": data}

    # Execute the code with locals/globals going into the dict above
    try:
        exec(PYTHON_CODES[filename], data)

And could provide a user accessor via a new pyinfra.local.get_variable:

def get_variable(name: str, default: Any = None) -> Any:
  if "__pyinfra__" in globals():
      return globals()["__pyinfra__"].get(name, default)
  return default

And the __pyinfra__ name spacing is to keep the scope in the files mostly clean and provides a space for other work like #828. I haven't thought this all the way through so may be overlooking an obvious issue. I'm happy to work on this when I get free time to do so, mostly looking to see if there's interest, if not then there's no need to add extra features for one user.

@Fizzadar
Copy link
Member

So the local.include function is already calling host.deploy under the hood (link) which already supports passing data, so this should be a pretty quick change.

Once done the data is accessible via host.data.

@Fizzadar Fizzadar added the CLI CLI mode specific issues. label Aug 25, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLI CLI mode specific issues.
Projects
None yet
Development

No branches or pull requests

2 participants