A typical boilerplate for Paternoster looks like this:
#!/usr/bin/env paternoster
- hosts: paternoster
vars:
success_msg: "all good!"
parameters:
- name: username
short: u
help: "name of the user to create"
type: paternoster.types.restricted_str
required: yes
type_params:
regex: '^[a-z]+$'
- hosts: localhost
tasks:
- debug: msg="creating user {{ param_username }}"
Inside vars
the following values can be set:
parameters
: command line parameters to parse, check and pass on to ansiblebecome_user
: usesudo
to execute the playbook as the given user (e.g.root
)check_user
: check that the user running the script is the one given heresuccess_msg
: print this message once the script has exited successfullydescription
: a short description of the script's purpose (for--help
output)
Each parameter is represented by a dictionary within the patermeters
list.
The values supplied there are passed onto pythons add_argument()
-function,
except for a few special ones:
Name | Description |
---|---|
name |
--long name on the command line |
short |
-s hort name on the command line |
type |
a class, which is parse and validate the value given by the user |
type_params |
optional parameters for the type class |
depends_on |
makes this argument depend on the presence of another one |
positional |
indicates whether the argument is a --keyword one (default) or positional. Must not be supplied together with required . |
prompt |
prompt the user for input, if the argument is not supplied. If the argument is required , it has to be set on the command line though. You can set this to True to use the default prompt, or to a (non empty) string to supply your own. The default prompt uses the name of the parameter. |
prompt_options |
dictionary containing optional settings for the prompt (see below for more information). |
All arguments to the script are passed to ansible as variables with the
param_
-prefix. This means that --domain foo.com
becomes the variable
param_domain
with value foo.com
.
There are a few special variables to provide the playbook further details about the environment it's in:
Name | Description |
---|---|
sudo_user |
the user who executed the script originally. If the script is not configured to run as root, this variable does not exist. |
script_name |
the filename of the script, which is currently executed (e.g. uberspace-add-domain ) |
In general the type-argument is mostly identical to the one supplied to
the python function add_argument()
.
This means that all standard python types (e.g. int
) can be used. Since
the input validation is quite weak on these types, paternoster supplies
a number of additional types. They can be referenced like paternoster.types.<name>
.
To enforce a certain level of security, all strings must be of the type
restricted_str
. This standard python str
or unicode
types may not
be used. This forces the developer the make a choice about the characters,
length and format of the given input.
type: paternoster.types.restricted_str
type_params:
# Either `regex` or `allowed_chars` must be supplied, but not both.
# anchored regular expression, which user input must match
regex: "^[a-z][a-z0-9]+$"
# regex character class, which contains all valid characters
allowed_chars: a-zab
# minimum length of a given input (defaults to 1), optional
minlen: 5
# maximum length of a given input (defaults to 255), optional
maxlen: 30
Integer which can optionally be restricted by a minimum as well as a maximum value. Both of these values are inclusive.
type: paternoster.types.restricted_int
type_params:
minimum: 0
maximum: 30
A fully qualified domain name with valid length, format and TLD.
type: paternoster.types.domain
type_params:
# whether to allow domains like "*.domain.com", defaults to false
wildcard: true
maxlen: 255
Note that domains given with a trailing dot (e.g. example.com.
) are normalized
to their dot-less form (e.g. example.com
). The maxlen
parameter restricts
simple string length before normalization.
A Uniform Resource Identifier (URI), with its scheme (protocol), domain (host)
and path. By default all of these parts are optional, defaulting to ''
or
/
(for path). This results in an empty string being a valid URI, representing
a scheme-less, domain-less URI with path /
.
type: paternoster.types.uri
type_params:
# whether to allow domains without scheme/protocol, defaults to true
optional_scheme: false
# whether to allow domains without domain/host, defaults to true
optional_domain: false
# options to pass onto the domain type, defaults to {}, see respective docs
domain_options:
wildcard: true
The parsed components can be accessed as dictionary keys in the resulting value:
{
"scheme": "https",
"domain": "uberspace.de",
"path": "/bla",
"full": "https://uberspace.de/bla"
}
As noted above, all components not present in the original URI will have a value
of ''
, except for path
which will default to /
.
In some cases a parameter may need another one to function correctly. A
real-life example of this might be the --namespace
parameter, which
depends on the --mailserver
parameter in uberspace-add-domain
. Such
a dependency can be expressed using the depends
-option of a pararmeter:
parameters:
- name: mailserver
short: m
help: add domain to the mailserver configuration
action: store_true
- name: namespace
short: e
help: use this namespace when adding a mail domain
type: paternoster.types.restricted_str
type_params:
allowed_chars: a-z0-9
depends_on: mailserver
Mutually exclusive parameters may never be given together by the caller (e.g.
--debug
and --quiet
). It is possible to specify any number of parameter
groups using the mutually_exclusive
key:
- hosts: paternoster
vars:
description: Do something
parameters:
- name: debug
short: d
action: store_true
- name: quiet
short: q
action: store_true
mutually_exclusive:
- ["debug", "quiet"]
With this configuration, the script may be invoked with --debug
or --quiet
alone, but never with both: --debug --quiet
.
Defines parameter groups of which at least one parameter must be given (e.g.
--webserver
or --mailserver
when adding a domain). This can be combined with
mutually_exclusive
to specify a group, of which exactly one must be given. It
is possible to specify any number of parameter groups using the
required_one_of
key:
- hosts: paternoster
vars:
description: Do something
parameters:
- name: webserver
short: w
action: store_true
- name: mailserver
short: m
action: store_true
required_one_of:
- ["webserver", "mailserver"]
With this configuration, the script may be invoked with --webserver
,
--mailserver
, or --webserver --mailserver
, but never without any arguments.
Name | Description |
---|---|
accept_empty |
if True, allow empty input. The default is to keep prompting until a non empty input is recieved. |
confirm |
ask for input confirmation (user has to repeat the entry). You can set this to True to use the default prompt, or to a (non empty) string to supply your own. |
confirm_error |
use this (non empty) string as error message if confirmation fails, instead of the default. |
no_echo |
if True: don't echo the user input on the screen. |
strip |
if True, remove whitespace at the start and end of the user input. |
There are multiple ways to let the user know, what's going on:
You can use the fail
-module
to display a error message to the user. The msg
option will be written
to stderr as-is, followed by an immediate exit of the script with exit-
code 1
.
To display a customized message when the playbook executes successfully
just set the success_msg
-variable, as demonstrated in the boilerplate above.
The message will be written to stdout as-is.
If you want to inform the user about the current task your playbook is
executing, you can use the debug
-module.
All messages sent by this module are written to stdout as-is. Note that
only messages with the default verbosity
value will be shown. All
other verbosity-levels can be used for actual debugging.