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: usesudoto 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--helpoutput)
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 |
-short 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: 30Integer 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: 30A 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: 255Note 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: trueThe 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: mailserverMutually 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.