Writing Modules¶
At the core of pyinfra lie facts and operations. These are namespaced as different modules. This guide should help you get started writing both operations and facts.
Operations¶
Operations are, in general, simple Python functions. They are passed the current deploy state and a target host, along with any operation arguments. The function reads state from the host, comparing it to the arguments, and yields commands.
Input: reserved arguments¶
The following keyword arguments are reserved for controlling how operations deploy, and
cannot be used within operations: sudo
, sudo_user
, ignore_errors
, serial
,
run_once
, timeout
, env
, name
, op
, get_pty
. In addition to this,
the first argument cannot accept set
objects, as these will be removed for use as
the operation name.
Output: commands¶
Operations are generator functions and yield
three types of command:
# Shell commands, simply represented by a string
yield 'echo "Shell!"'
# File uploads represented by a tuple
yield (filename_or_io, remote_filename)
# Python functions represented by a tuple
yield (function, args_list, kwargs_dict)
# Additionally, commands can be wrapped in a dict, overriding sudo/sudo_user
yield {
'command': 'echo "Shell!"',
'sudo': True
}
Example: managing files¶
This is a simplified version of the files.file
operation, which will create/remove a
remote file based on the present
kwargs:
from pyinfra.api import operation
@operation
def file(state, host, name, present=True):
'''
Manage the state of files.
+ name: name/path of the remote file
+ present: whether the file should exist
'''
info = host.fact.file(name)
# Not a file?!
if info is False:
raise OperationError('{0} exists and is not a file'.format(name))
# Doesn't exist & we want it
if info is None and present:
yield 'touch {0}'.format(name)
# It exists and we don't want it
elif info and not present:
yield 'rm -f {0}'.format(name)
Facts¶
Facts are written as Python classes. They provide a command
(as a string or method)
and a process
function. The command is executed on the target host and the output
passed (as a list
of lines) to the process
handler to generate fact data.
Facts can output any data structure, normally a list
or dict
. They often make
heavy use of regex to parse the output.
Example: getting the sha1 of a file¶
This fact returns a list of files found in a given directory.
from pyinfra.api import FactBase
class FindFiles(FactBase):
'''
Returns a list of files from a start point, recursively using find.
'''
def command(self, name):
# Find files in the given location
return 'find {0} -type f'.format(name)
def process(self, output):
# Return the list of lines (files) as-is
return output