diff --git a/docs/extending.rst b/docs/extending.rst new file mode 100644 index 000000000..361811f06 --- /dev/null +++ b/docs/extending.rst @@ -0,0 +1,139 @@ +Extending Pyinfra +================= + +Every site needs an integration or fact which is unique to them. The pages below here describe the process of building a pip installable pyinfra +package with one or more custom facts, connectors, or operations. + +Packaging for Pyinfra extensions +-------------------------------- + +Create venv + +:: + + virtualenv ~/.venvs/pyinfra_hacking + +Install dependencies + +:: + + source ~/.venvs/pyinfra_hacking/bin/activate + pip install build setuptools + +Create development environment + +:: + + mkdir -p ~/pyinfra_extension/pyinfra_extension/ + cd ~/pyinfra_extension + echo 'pyinfra' > requirements.txt + echo 'pyinfra_*egg-info' >> .gitignore + echo 'dist/' >> .gitignore + touch pyinfra_extension/__init__.py + git init . + git add . + git commit -avm 'environment prepared' + +Add a ``pyproject.toml`` file, its contents should look something like the following: + +:: + + [build-system] + requires = ["setuptools"] + build-backend = "setuptools.build_meta" + + [project] + name = "pyinfra_extension" + version = "0.0.1" + dependencies = [ + "pyinfra", + ] + +If creating a custom Inventory/Execution connector, add the following too: + +:: + + [project.entry-points.'pyinfra.connectors'] + # Key = Entry point name + # Value = module_path:class_name + extendor = 'pyinfra_extension.connectors:ExtendedConnector' + + +Build it! + +:: + + python -m build + +Install it! This will create an editable install so your module will load in pyinfra but still be editable in this repository. + +:: + + pip install --editable . + + +And with that the extension is ready to go! + +Files for your extension should be in ``pyinfra_extension``, eg: + +:: + + ~/pyinfra_extension$ ls -1 pyinfra_extension/ + connectors.py + facts.py + __init__.py + operations.py + other_relevant_file.py + +And the connector you registered in ``pyproject.toml`` needs to match the path to, and class name in, ``connectors.py``: + +:: + + ~/pyinfra_extension$ grep ExtendedConnector pyinfra_extension/connectors.py + class ExtendedConnector(BaseConnector): + + +Custom libraries +---------------- + +If additional libraries are needed in a custom plugin they should be included with it and imported by connectors/facts/... as required. + + +Custom facts +------------ + +See existing docs, no tips here yet + +Custom connectors +----------------- + +Check out :doc:`the writing connectors guide <./api/connectors>` for the bulk of information related to connectors. + + +Exceptions +---------- + +pyinfra exceptions +- raising in my code +- handling generated by pyinfra + +Debugging +--------- + +During development a healthy scattering of ``print()``'s is possible and will output data to the screen. + +Despite that, its better to use the built in logging from the start. ``info`` and ``warning`` level logs are displayed by default and the log level can be +configured. + +:: + from pyinfra import logger + ... + logger.warning('{} not found in environment'.format(ke)) + ... + logger.info('name is {}'.format(name)) + +Tests +----- + +Testing is covered in :doc:`Contributing <./docs/contributing>`; I haven't checked it yet +