From c027acba1c4532688068d9f1fae94c1869ccb463 Mon Sep 17 00:00:00 2001
From: jurgenhaas <juergen@paragon-es.de>
Date: Sun, 30 Oct 2016 15:07:35 +0100
Subject: [PATCH] Change script framework from Python to Yaml

---
 ansible-script.py              | 31 +++++++++++++---------
 lib/general.py                 | 48 +++++++++++++++++++++++++++++-----
 scripts/__init__.py            |  0
 scripts/apache-config.yml      | 22 ++++++++++++++++
 scripts/apacheconfig.py        | 15 -----------
 scripts/bigfiles.py            | 18 -------------
 scripts/bigfiles.yml           | 17 ++++++++++++
 scripts/composer-update.py     | 16 ------------
 scripts/composer-update.yml    | 14 ++++++++++
 scripts/connectivity.py        | 13 ---------
 scripts/connectivity.yml       | 12 +++++++++
 scripts/cronjobs.py            | 12 ---------
 scripts/cronjobs.yml           |  6 +++++
 scripts/drupal-config.yml      | 33 +++++++++++++++++++++++
 scripts/drupal-deploy.yml      | 31 ++++++++++++++++++++++
 scripts/drupal.py              | 21 ---------------
 scripts/drupaldeploy.py        | 19 --------------
 scripts/drush-aliases.yml      | 13 +++++++++
 scripts/elastalert.py          | 13 ---------
 scripts/elastalert.yml         | 13 +++++++++
 scripts/firewall-config.py     | 14 ----------
 scripts/firewall-config.yml    | 13 +++++++++
 scripts/firewall-unprotect.py  | 15 -----------
 scripts/firewall-unprotect.yml | 16 ++++++++++++
 scripts/getdrushaliases.py     | 13 ---------
 scripts/haproxy-certs.yml      | 17 ++++++++++++
 scripts/haproxy-config.yml     | 17 ++++++++++++
 scripts/haproxycerts.py        | 14 ----------
 scripts/haproxyconfig.py       | 14 ----------
 scripts/hosts.py               | 13 ---------
 scripts/hosts.yml              |  7 +++++
 scripts/jailkit-update.yml     | 22 ++++++++++++++++
 scripts/jailkit-upgrade.yml    | 15 +++++++++++
 scripts/jailkit-user.yml       | 20 ++++++++++++++
 scripts/jailkitupdate.py       | 17 ------------
 scripts/jailkitupgrade.py      | 14 ----------
 scripts/jailkituser.py         | 16 ------------
 scripts/nextcloud.py           | 14 ----------
 scripts/nextcloud.yml          | 21 +++++++++++++++
 scripts/piwik.py               | 14 ----------
 scripts/piwik.yml              | 21 +++++++++++++++
 scripts/role.py                | 15 -----------
 scripts/role.yml               | 15 +++++++++++
 scripts/sanity.py              | 17 ------------
 scripts/sanity.yml             | 24 +++++++++++++++++
 scripts/shells.py              | 13 ---------
 scripts/shells.yml             | 17 ++++++++++++
 scripts/users.py               | 15 -----------
 scripts/users.yml              | 12 +++++++++
 scripts/varnish-config.yml     | 13 +++++++++
 scripts/varnishconfig.py       | 13 ---------
 scripts/youtrack.py            | 13 ---------
 scripts/youtrack.yml           | 18 +++++++++++++
 wiki                           |  2 +-
 54 files changed, 489 insertions(+), 392 deletions(-)
 delete mode 100644 scripts/__init__.py
 create mode 100644 scripts/apache-config.yml
 delete mode 100755 scripts/apacheconfig.py
 delete mode 100755 scripts/bigfiles.py
 create mode 100644 scripts/bigfiles.yml
 delete mode 100755 scripts/composer-update.py
 create mode 100644 scripts/composer-update.yml
 delete mode 100755 scripts/connectivity.py
 create mode 100644 scripts/connectivity.yml
 delete mode 100755 scripts/cronjobs.py
 create mode 100644 scripts/cronjobs.yml
 create mode 100644 scripts/drupal-config.yml
 create mode 100644 scripts/drupal-deploy.yml
 delete mode 100755 scripts/drupal.py
 delete mode 100755 scripts/drupaldeploy.py
 create mode 100644 scripts/drush-aliases.yml
 delete mode 100755 scripts/elastalert.py
 create mode 100644 scripts/elastalert.yml
 delete mode 100755 scripts/firewall-config.py
 create mode 100644 scripts/firewall-config.yml
 delete mode 100755 scripts/firewall-unprotect.py
 create mode 100644 scripts/firewall-unprotect.yml
 delete mode 100755 scripts/getdrushaliases.py
 create mode 100644 scripts/haproxy-certs.yml
 create mode 100644 scripts/haproxy-config.yml
 delete mode 100755 scripts/haproxycerts.py
 delete mode 100755 scripts/haproxyconfig.py
 delete mode 100755 scripts/hosts.py
 create mode 100644 scripts/hosts.yml
 create mode 100644 scripts/jailkit-update.yml
 create mode 100644 scripts/jailkit-upgrade.yml
 create mode 100644 scripts/jailkit-user.yml
 delete mode 100755 scripts/jailkitupdate.py
 delete mode 100755 scripts/jailkitupgrade.py
 delete mode 100755 scripts/jailkituser.py
 delete mode 100755 scripts/nextcloud.py
 create mode 100644 scripts/nextcloud.yml
 delete mode 100755 scripts/piwik.py
 create mode 100644 scripts/piwik.yml
 delete mode 100755 scripts/role.py
 create mode 100644 scripts/role.yml
 delete mode 100755 scripts/sanity.py
 create mode 100644 scripts/sanity.yml
 delete mode 100755 scripts/shells.py
 create mode 100644 scripts/shells.yml
 delete mode 100755 scripts/users.py
 create mode 100644 scripts/users.yml
 create mode 100644 scripts/varnish-config.yml
 delete mode 100755 scripts/varnishconfig.py
 delete mode 100755 scripts/youtrack.py
 create mode 100644 scripts/youtrack.yml

diff --git a/ansible-script.py b/ansible-script.py
index c8915b71..c1e5d3c3 100755
--- a/ansible-script.py
+++ b/ansible-script.py
@@ -11,19 +11,24 @@ to be executed as the first argument.
 import argparse
 import sys
 import os
-import importlib
+import yaml
 from tabulate import tabulate
 from lib import general
 
+path = os.path.dirname(os.path.realpath(__file__)) + os.path.sep + 'scripts' + os.path.sep
+
 
 def list():
     scripts = []
-    for file in sorted(os.listdir(os.path.dirname(os.path.realpath(__file__)) + os.path.sep + 'scripts')):
-        if file != '__init__.py' and '.pyc' not in file:
-            scriptname = file.split('.')[0]
-            script = importlib.import_module('.' + scriptname, package='scripts')
-            scripts.append([scriptname, script.__doc__.splitlines()[0]])
-
+    for file in sorted(os.listdir(path)):
+        name, ext = os.path.splitext(file)
+        if ext == '.yml':
+            with open(path + file, 'r') as config:
+                try:
+                    script = yaml.load(config)
+                    scripts.append([name, script['description']])
+                except yaml.YAMLError:
+                    pass
     print(tabulate(scripts, headers=['Script', 'Description']))
     exit(0)
 
@@ -40,12 +45,12 @@ def script():
     if arg == 'list':
         list()
 
-    try:
-        script = importlib.import_module('.' + arg, package='scripts')
-    except Exception:
-        raise Exception('Script %s does not exist.' % (arg))
-
-    return script
+    with open(path + arg + '.yml', 'r') as config:
+        try:
+            return yaml.load(config)
+        except Exception:
+            pass
+    raise Exception('Script %s does not exist.' % (arg))
 
 
 parser = argparse.ArgumentParser(description='Ansible script by Paragon',
diff --git a/lib/general.py b/lib/general.py
index 88fc7d2c..58eeda63 100644
--- a/lib/general.py
+++ b/lib/general.py
@@ -4,6 +4,7 @@ import yaml
 import uservars
 import threading
 import Queue
+import types
 import window
 from subprocess import Popen, PIPE, STDOUT
 
@@ -25,16 +26,24 @@ def run(parser, script=None):
                             help='Disable GUI')
     if not os.path.exists(path + 'inventory/group_vars'):
         parser.add_argument('--company', default=os.environ.get('ANSIBLE_COMPANY', None),
-                            required=(not isGitlabUser(env)),
+                            required=companyRequired(env),
                             help='Only useful if inventories from multiple companies are installed')
         parser.add_argument('--include-local', action='store_true', default=False,
                             help='If company=all, this would also include the local inventory, default to False')
 
     if script:
-        parser.description = script.__doc__
+        parser.description = script['description']
         parser.add_argument('--custom', action='store_true', default=False,
                             help='Only run a custom playbook and ignore the global one')
-        script.extend(parser)
+        if 'cli' in script:
+            for type in ['arguments', 'options']:
+                prefix = '--' if type == 'options' else ''
+                if type in script['cli']:
+                    for item in script['cli'][type]:
+                        parser.add_argument(prefix + item, **script['cli'][type][item])
+            if 'defaults' in script['cli']:
+                for item in script['cli']['defaults']:
+                    parser.set_defaults(**{item: script['cli']['defaults'][item]})
 
     args, extras = parser.parse_known_args()
 
@@ -42,7 +51,12 @@ def run(parser, script=None):
         window.guiAvailable = False
 
     if script:
-        script.append(args)
+        if 'arguments' in script:
+            for item in script['arguments']:
+                value = script['arguments'][item]
+                if not isinstance(value, types.StringTypes):
+                    value = ','.join(value)
+                setattr(args, item, value)
 
     if 'playbook' in args and 'limit' in args:
         extras.append('--limit=' + args.limit)
@@ -110,8 +124,8 @@ def followUp(script, args):
     if error_seen:
         exit(1)
 
-    if script and hasattr(script, 'follower'):
-        cmd = ['ascr', script.follower(), '--limit=' + args.limit]
+    if 'follower' in script:
+        cmd = ['ascr', script['follower'], '--limit=' + args.limit]
         if hasattr(args, 'company'):
             cmd.append('--company=' + args.company)
         if not window.guiAvailable:
@@ -144,6 +158,12 @@ def startThreads(company, args, files, path, extras, pathSecrets, script):
             thread.join()
 
 
+def companyRequired(env):
+    if 'ANSIBLE_COMPANY' in env:
+        return False
+    return not isGitlabUser(env)
+
+
 def isGitlabUser(env):
     return ('USER' in env and env['USER'] == 'gitlab-runner')
 
@@ -209,7 +229,21 @@ def main(args, extras, path, pathSecrets, company = None, script = None):
     cmd.append('--extra-vars={excluded_roles: ' + json.dumps(excluded_roles) + '}')
 
     if script:
-        script.build(cmd, args)
+        if 'command' in script:
+            for item in script['command']:
+                condition = True
+                if 'condition' in item:
+                    condition = bool(getattr(args, item['condition']))
+                if condition:
+                    value = item['value']
+                    if not isinstance(value, types.StringTypes):
+                        value = ','.join(value)
+                    if 'args' in item:
+                        commandargs = []
+                        for commandarg in item['args']:
+                            commandargs.append(getattr(args, commandarg))
+                        value = value % tuple(commandargs)
+                    cmd.append('--' + item['name'] + '=' + value)
 
     # Append more CLI options
     for extra in extras:
diff --git a/scripts/__init__.py b/scripts/__init__.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/scripts/apache-config.yml b/scripts/apache-config.yml
new file mode 100644
index 00000000..b5be99d2
--- /dev/null
+++ b/scripts/apache-config.yml
@@ -0,0 +1,22 @@
+description: 'Quickly configure Apache'
+cli:
+  options:
+    application:
+      default: 'apache'
+      help: 'The application to configure Apache for, e.g. apache, drupal, piwk, nextcloud'
+arguments:
+  playbook: 'role'
+  roles_exclude:
+    - 'commonauth'
+    - 'commonconnect'
+    - 'common'
+    - 'php'
+    - 'jailkit'
+command:
+  - name: 'tags'
+    value: 'ApacheConfig'
+  - name: 'extra-vars'
+    value: 'hosts=%s role=%s'
+    args:
+      - 'limit'
+      - 'application'
diff --git a/scripts/apacheconfig.py b/scripts/apacheconfig.py
deleted file mode 100755
index aed02752..00000000
--- a/scripts/apacheconfig.py
+++ /dev/null
@@ -1,15 +0,0 @@
-"""Quickly configure Apache"""
-
-def extend(parser):
-    parser.add_argument('--application', default='apache',
-                        help='The application to configure Apache for, e.g. apache, drupal, piwk, nextcloud')
-
-
-def append(args):
-    args.playbook = 'role'
-    args.roles_exclude = 'commonauth,commonconnect,common,php,jailkit'
-
-
-def build(cmd, args):
-    cmd.append('--tags=ApacheConfig')
-    cmd.append('--extra-vars=hosts=' + args.limit + ' role=' + args.application)
diff --git a/scripts/bigfiles.py b/scripts/bigfiles.py
deleted file mode 100755
index 7da93e7b..00000000
--- a/scripts/bigfiles.py
+++ /dev/null
@@ -1,18 +0,0 @@
-"""Find big files / directories"""
-
-def extend(parser):
-    parser.add_argument('--depth', default=5,
-                        help='How many directories deep this should parse')
-    parser.add_argument('--threshold', default='1G',
-                        help='Only show directories bigger than this')
-
-
-def append(args):
-    pass
-
-
-def build(cmd, args):
-    cmd.append('-m')
-    cmd.append('command')
-    cmd.append('-a')
-    cmd.append('du -xchd ' + str(args.depth) + ' --threshold=' + args.threshold + ' /')
diff --git a/scripts/bigfiles.yml b/scripts/bigfiles.yml
new file mode 100644
index 00000000..68b8886f
--- /dev/null
+++ b/scripts/bigfiles.yml
@@ -0,0 +1,17 @@
+description: 'Find big files / directories'
+cli:
+  options:
+    depth:
+      default: 5
+      help: 'How many directories deep this should parse'
+    threshold:
+      default: '1G'
+      help: 'Only show directories bigger than this'
+command:
+  - name: 'module-name'
+    value: 'command'
+  - name: 'args'
+    value: 'du -xchd %s --threshold=%s /'
+    args:
+      - 'depth'
+      - 'threshold'
diff --git a/scripts/composer-update.py b/scripts/composer-update.py
deleted file mode 100755
index 2f676b94..00000000
--- a/scripts/composer-update.py
+++ /dev/null
@@ -1,16 +0,0 @@
-"""Update Composer itself and global packages"""
-
-def extend(parser):
-    parser.set_defaults(limit='webserver')
-
-
-def append(args):
-    args.playbook = 'role'
-
-
-def build(cmd, args):
-    cmd.append('--extra-vars=hosts=' + args.limit + ' role=composer')
-    cmd.append('--tags=update')
-
-def follower():
-    return 'jailkitupgrade'
diff --git a/scripts/composer-update.yml b/scripts/composer-update.yml
new file mode 100644
index 00000000..501c6eaf
--- /dev/null
+++ b/scripts/composer-update.yml
@@ -0,0 +1,14 @@
+description: 'Update Composer itself and global packages'
+cli:
+  defaults:
+    limit: 'webserver'
+arguments:
+  playbook: 'role'
+command:
+  - name: 'extra-vars'
+    value: 'hosts=%s role=composer'
+    args:
+      - 'limit'
+  - name: 'tags'
+    value: 'update'
+follower: 'jailkitupgrade'
diff --git a/scripts/connectivity.py b/scripts/connectivity.py
deleted file mode 100755
index fe004e87..00000000
--- a/scripts/connectivity.py
+++ /dev/null
@@ -1,13 +0,0 @@
-"""Update hosts and ssh config"""
-
-def extend(parser):
-    parser.set_defaults(limit='all')
-    parser.set_defaults(include_local=True)
-
-
-def append(args):
-    args.playbook = 'role'
-
-
-def build(cmd, args):
-    cmd.append('--extra-vars=hosts=' + args.limit + ' role=commonconnect')
diff --git a/scripts/connectivity.yml b/scripts/connectivity.yml
new file mode 100644
index 00000000..30284ec0
--- /dev/null
+++ b/scripts/connectivity.yml
@@ -0,0 +1,12 @@
+description: 'Update hosts and ssh config'
+cli:
+  defaults:
+    limit: 'all'
+    include_local: True
+arguments:
+  playbook: 'role'
+command:
+  - name: 'extra-vars'
+    value: 'hosts=%s role=commonconnect'
+    args:
+      - 'limit'
diff --git a/scripts/cronjobs.py b/scripts/cronjobs.py
deleted file mode 100755
index 8c6aa009..00000000
--- a/scripts/cronjobs.py
+++ /dev/null
@@ -1,12 +0,0 @@
-"""Update Cron Jobs"""
-
-def extend(parser):
-    pass
-
-
-def append(args):
-    args.playbook = 'farm'
-
-
-def build(cmd, args):
-    cmd.append('--tags=cron')
diff --git a/scripts/cronjobs.yml b/scripts/cronjobs.yml
new file mode 100644
index 00000000..93d7973b
--- /dev/null
+++ b/scripts/cronjobs.yml
@@ -0,0 +1,6 @@
+description: 'Update Cron Jobs'
+arguments:
+  playbook: 'farm'
+command:
+  - name: 'tags'
+    value: 'cron'
diff --git a/scripts/drupal-config.yml b/scripts/drupal-config.yml
new file mode 100644
index 00000000..8f180637
--- /dev/null
+++ b/scripts/drupal-config.yml
@@ -0,0 +1,33 @@
+description: 'Quickly configure Drupal sites'
+cli:
+  options:
+    site:
+      default: None
+      help: 'The id of a site if only one of the defined sites should be updated'
+    quick:
+      action: 'store_true'
+      default: False
+      help: 'Only Drupal itself, not the CLI or JailKit'
+  defaults:
+    limit: 'webserver-drupal'
+arguments:
+  playbook: 'role'
+  roles_exclude:
+    - 'commonauth'
+    - 'commonconnect'
+    - 'common'
+    - 'php'
+    - 'apache'
+command:
+  - name: 'extra-vars'
+    value: 'hosts=%s role=drupal'
+    args:
+      - 'limit'
+  - name: 'extra-vars'
+    condition: 'site'
+    value: 'limit_drupal_site=%s'
+    args:
+      - 'site'
+  - name: 'start-at-task'
+    condition: 'quick'
+    value: 'Drupal Role'
diff --git a/scripts/drupal-deploy.yml b/scripts/drupal-deploy.yml
new file mode 100644
index 00000000..51a93092
--- /dev/null
+++ b/scripts/drupal-deploy.yml
@@ -0,0 +1,31 @@
+description: 'Quickly re-deploy a Drupal site'
+cli:
+  arguments:
+    host:
+      default: None
+      help: 'The hostname on which to re-reploy Drupal'
+    site:
+      default: None
+      help: 'The id of a site'
+arguments:
+  playbook: 'role'
+  roles_exclude:
+    - 'commonauth'
+    - 'commonconnect'
+    - 'common'
+    - 'php'
+    - 'apache'
+    - 'jailkit'
+command:
+  - name: 'tags'
+    value: 'deploy'
+  - name: 'extra-vars'
+    value: 'hosts=%s role=drupal'
+    args:
+      - 'host'
+  - name: 'extra-vars'
+    value: 'limit_drupal_site=%s'
+    args:
+      - 'site'
+  - name: 'start-at-task'
+    value: 'Install Drupal'
diff --git a/scripts/drupal.py b/scripts/drupal.py
deleted file mode 100755
index 7e861b90..00000000
--- a/scripts/drupal.py
+++ /dev/null
@@ -1,21 +0,0 @@
-"""Quickly configure Drupal sites"""
-
-def extend(parser):
-    parser.add_argument('--site', default=None,
-                        help='The id of a site if only one of the defined sites should be updated')
-    parser.add_argument('--quick', action='store_true', default=False,
-                        help='Only Drupal itself, not the CLI or JailKit')
-    parser.set_defaults(limit='webserver-drupal')
-
-
-def append(args):
-    args.playbook = 'role'
-    args.roles_exclude = 'commonauth,commonconnect,common,php,apache'
-
-
-def build(cmd, args):
-    cmd.append('--extra-vars=hosts=' + args.limit + ' role=drupal')
-    if args.site:
-        cmd.append('--extra-vars=limit_drupal_site=' + args.site)
-    if args.quick:
-        cmd.append('--start-at-task=Drupal Role')
diff --git a/scripts/drupaldeploy.py b/scripts/drupaldeploy.py
deleted file mode 100755
index 12536b4b..00000000
--- a/scripts/drupaldeploy.py
+++ /dev/null
@@ -1,19 +0,0 @@
-"""Quickly re-deploy a Drupal site"""
-
-def extend(parser):
-    parser.add_argument('host', default=None,
-                        help='The hostname on which to re-reploy Drupal')
-    parser.add_argument('site', default=None,
-                        help='The id of a site')
-
-
-def append(args):
-    args.playbook = 'role'
-    args.roles_exclude = 'commonauth,commonconnect,common,php,apache,jailkit'
-
-
-def build(cmd, args):
-    cmd.append('--tags=deploy')
-    cmd.append('--extra-vars=hosts=' + args.host + ' role=drupal')
-    cmd.append('--extra-vars=limit_drupal_site=' + args.site)
-    cmd.append('--start-at-task=Install Drupal')
diff --git a/scripts/drush-aliases.yml b/scripts/drush-aliases.yml
new file mode 100644
index 00000000..74ccea8d
--- /dev/null
+++ b/scripts/drush-aliases.yml
@@ -0,0 +1,13 @@
+description: 'Retrieve and adjust Drush aliases from remote host(s)'
+cli:
+  defaults:
+    limit: 'webserver-drupal'
+arguments:
+  playbook: 'role'
+command:
+  - name: 'tags'
+    value: 'DrushUpdateAliases'
+  - name: 'extra-vars'
+    value: 'hosts=%s role=drush'
+    args:
+      - 'limit'
diff --git a/scripts/elastalert.py b/scripts/elastalert.py
deleted file mode 100755
index 0365a84f..00000000
--- a/scripts/elastalert.py
+++ /dev/null
@@ -1,13 +0,0 @@
-"""Update rules on ElastAlert hosts"""
-
-def extend(parser):
-    parser.set_defaults(limit='logserver')
-
-
-def append(args):
-    args.playbook = 'role'
-
-
-def build(cmd, args):
-    cmd.append('--tags=Rules')
-    cmd.append('--extra-vars=hosts=' + args.limit + ' role=elasticsearch')
diff --git a/scripts/elastalert.yml b/scripts/elastalert.yml
new file mode 100644
index 00000000..18635620
--- /dev/null
+++ b/scripts/elastalert.yml
@@ -0,0 +1,13 @@
+description: 'Update rules on ElastAlert hosts'
+cli:
+  defaults:
+    limit: 'logserver'
+arguments:
+  playbook: 'role'
+command:
+  - name: 'tags'
+    value: 'Rules'
+  - name: 'extra-vars'
+    value: 'hosts=%s role=elasticsearch'
+    args:
+      - 'limit'
diff --git a/scripts/firewall-config.py b/scripts/firewall-config.py
deleted file mode 100755
index 056cea96..00000000
--- a/scripts/firewall-config.py
+++ /dev/null
@@ -1,14 +0,0 @@
-"""Rebuild Firewall Configuration"""
-
-def extend(parser):
-    pass
-
-
-def append(args):
-    args.playbook = 'role'
-    args.roles_exclude = 'commonauth,commonconnect'
-
-
-def build(cmd, args):
-    cmd.append('--extra-vars=hosts=' + args.limit + ' role=common')
-    cmd.append('--tags=firewall')
diff --git a/scripts/firewall-config.yml b/scripts/firewall-config.yml
new file mode 100644
index 00000000..bf561eae
--- /dev/null
+++ b/scripts/firewall-config.yml
@@ -0,0 +1,13 @@
+description: 'Rebuild Firewall Configuration'
+arguments:
+  playbook: 'role'
+  roles_exclude:
+    - 'commonauth'
+    - 'commonconnect'
+command:
+  - name: 'tags'
+    value: 'firewall'
+  - name: 'extra-vars'
+    value: 'hosts=%s role=common'
+    args:
+      - 'limit'
diff --git a/scripts/firewall-unprotect.py b/scripts/firewall-unprotect.py
deleted file mode 100755
index 31bbf1f8..00000000
--- a/scripts/firewall-unprotect.py
+++ /dev/null
@@ -1,15 +0,0 @@
-"""Switch Firewall to unprotected mode for a period of time"""
-
-def extend(parser):
-    parser.add_argument('--unprotect-period', default=None,
-                        help='Number of minutes before the firewall goes into protected mode again')
-
-
-def append(args):
-    args.playbook = 'firewall'
-
-
-def build(cmd, args):
-    cmd.append('--tags=unprotect')
-    if args.unprotect_period:
-        cmd.append('--extra-vars=unprotect_period=' + args.unprotect_period)
diff --git a/scripts/firewall-unprotect.yml b/scripts/firewall-unprotect.yml
new file mode 100644
index 00000000..895e7eb4
--- /dev/null
+++ b/scripts/firewall-unprotect.yml
@@ -0,0 +1,16 @@
+description: 'Switch Firewall to unprotected mode for a period of time'
+cli:
+  options:
+    unprotect-period:
+      default: None
+      help: 'Number of minutes before the firewall goes into protected mode again'
+arguments:
+  playbook: 'firewall'
+command:
+  - name: 'tags'
+    value: 'unprotect'
+  - name: 'extra-vars'
+    condition: 'unprotect_period'
+    value: 'unprotect_period=%s'
+    args:
+      - 'unprotect_period'
diff --git a/scripts/getdrushaliases.py b/scripts/getdrushaliases.py
deleted file mode 100755
index 99e958fb..00000000
--- a/scripts/getdrushaliases.py
+++ /dev/null
@@ -1,13 +0,0 @@
-"""Retrieve and adjust Drush aliases from remote host(s)"""
-
-def extend(parser):
-    parser.set_defaults(limit='webserver-drupal')
-
-
-def append(args):
-    args.playbook = 'role'
-
-
-def build(cmd, args):
-    cmd.append('--tags=DrushUpdateAliases')
-    cmd.append('--extra-vars=hosts=' + args.limit + ' role=drush')
diff --git a/scripts/haproxy-certs.yml b/scripts/haproxy-certs.yml
new file mode 100644
index 00000000..42e8a591
--- /dev/null
+++ b/scripts/haproxy-certs.yml
@@ -0,0 +1,17 @@
+description: 'Build SSL Certs for HaProxy'
+cli:
+  defaults:
+    limit: 'proxyserver'
+arguments:
+  playbook: 'role'
+  roles_exclude:
+    - 'commonauth'
+    - 'commonconnect'
+    - 'common'
+command:
+  - name: 'tags'
+    value: 'Certs'
+  - name: 'extra-vars'
+    value: 'hosts=%s role=haproxy'
+    args:
+      - 'limit'
diff --git a/scripts/haproxy-config.yml b/scripts/haproxy-config.yml
new file mode 100644
index 00000000..ca5ecb67
--- /dev/null
+++ b/scripts/haproxy-config.yml
@@ -0,0 +1,17 @@
+description: 'Quickly configure HaProxy'
+cli:
+  defaults:
+    limit: 'proxyserver'
+arguments:
+  playbook: 'role'
+  roles_exclude:
+    - 'commonauth'
+    - 'commonconnect'
+    - 'common'
+command:
+  - name: 'tags'
+    value: 'Config'
+  - name: 'extra-vars'
+    value: 'hosts=%s role=haproxy'
+    args:
+      - 'limit'
diff --git a/scripts/haproxycerts.py b/scripts/haproxycerts.py
deleted file mode 100755
index 5e3d87c3..00000000
--- a/scripts/haproxycerts.py
+++ /dev/null
@@ -1,14 +0,0 @@
-"""Build SSL Certs for HaProxy"""
-
-def extend(parser):
-    parser.set_defaults(limit='proxyserver')
-
-
-def append(args):
-    args.playbook = 'role'
-    args.roles_exclude = 'commonauth,commonconnect,common'
-
-
-def build(cmd, args):
-    cmd.append('--tags=Certs')
-    cmd.append('--extra-vars=hosts=' + args.limit + ' role=haproxy')
diff --git a/scripts/haproxyconfig.py b/scripts/haproxyconfig.py
deleted file mode 100755
index 75b66910..00000000
--- a/scripts/haproxyconfig.py
+++ /dev/null
@@ -1,14 +0,0 @@
-"""Quickly configure HaProxy"""
-
-def extend(parser):
-    parser.set_defaults(limit='proxyserver')
-
-
-def append(args):
-    args.playbook = 'role'
-    args.roles_exclude = 'commonauth,commonconnect,common'
-
-
-def build(cmd, args):
-    cmd.append('--tags=Config')
-    cmd.append('--extra-vars=hosts=' + args.limit + ' role=haproxy')
diff --git a/scripts/hosts.py b/scripts/hosts.py
deleted file mode 100755
index 1de50d3c..00000000
--- a/scripts/hosts.py
+++ /dev/null
@@ -1,13 +0,0 @@
-"""Locally update host information for all inventories"""
-
-def extend(parser):
-    parser.set_defaults(company='all')
-    parser.set_defaults(limit='all')
-
-
-def append(args):
-    args.playbook = 'hosts'
-
-
-def build(cmd, args):
-    pass
diff --git a/scripts/hosts.yml b/scripts/hosts.yml
new file mode 100644
index 00000000..0fb82e80
--- /dev/null
+++ b/scripts/hosts.yml
@@ -0,0 +1,7 @@
+description: 'Locally update host information for all inventories'
+cli:
+  defaults:
+    company: 'all'
+    limit: 'all'
+arguments:
+  playbook: 'hosts'
diff --git a/scripts/jailkit-update.yml b/scripts/jailkit-update.yml
new file mode 100644
index 00000000..fecf1872
--- /dev/null
+++ b/scripts/jailkit-update.yml
@@ -0,0 +1,22 @@
+description: 'Force updating all Jails'
+cli:
+  options:
+    site:
+      default: None
+      help: 'The id of a site if only one of the defined sites should be updated'
+  defaults:
+    limit: 'webserver-drupal'
+arguments:
+  playbook: 'role'
+command:
+  - name: 'extra-vars'
+    value: 'hosts=%s role=jailkit jailsite_init_force=True'
+    args:
+      - 'limit'
+  - name: 'start-at-task'
+    value: 'JailKit Role'
+  - name: 'extra-vars'
+    condition: 'site'
+    value: 'limit_drupal_site=%s'
+    args:
+      - 'site'
diff --git a/scripts/jailkit-upgrade.yml b/scripts/jailkit-upgrade.yml
new file mode 100644
index 00000000..3956aa5c
--- /dev/null
+++ b/scripts/jailkit-upgrade.yml
@@ -0,0 +1,15 @@
+description: 'Update OS components in all Jails'
+cli:
+  defaults:
+    limit: 'webserver-drupal'
+arguments:
+  playbook: 'role'
+command:
+  - name: 'extra-vars'
+    value: 'hosts=%s role=jailkit'
+    args:
+      - 'limit'
+  - name: 'start-at-task'
+    value: 'JailKit Role'
+  - name: 'tags'
+    value: 'UpdateJails'
diff --git a/scripts/jailkit-user.yml b/scripts/jailkit-user.yml
new file mode 100644
index 00000000..42cae502
--- /dev/null
+++ b/scripts/jailkit-user.yml
@@ -0,0 +1,20 @@
+description: 'Init and update users in Jails'
+cli:
+  options:
+    site:
+      default: None
+      help: 'The id of a site if only one of the defined sites should be updated'
+  defaults:
+    limit: 'webserver-drupal'
+arguments:
+  playbook: 'user'
+command:
+  - name: 'tags'
+    value:
+      - 'JailUserInit'
+      - 'SetPermissions'
+  - name: 'extra-vars'
+    condition: 'site'
+    value: 'limit_drupal_site=%s'
+    args:
+      - 'site'
diff --git a/scripts/jailkitupdate.py b/scripts/jailkitupdate.py
deleted file mode 100755
index 28c5ee7a..00000000
--- a/scripts/jailkitupdate.py
+++ /dev/null
@@ -1,17 +0,0 @@
-"""Force updating all Jails"""
-
-def extend(parser):
-    parser.add_argument('--site', default=None,
-                        help='The id of a site if only one of the defined sites should be updated')
-    parser.set_defaults(limit='webserver-drupal')
-
-
-def append(args):
-    args.playbook = 'role'
-
-
-def build(cmd, args):
-    cmd.append('--extra-vars=hosts=' + args.limit + ' role=jailkit jailsite_init_force=True')
-    cmd.append('--start-at-task=JailKit Role')
-    if args.site:
-        cmd.append('--extra-vars=limit_drupal_site=' + args.site)
diff --git a/scripts/jailkitupgrade.py b/scripts/jailkitupgrade.py
deleted file mode 100755
index 0e06590e..00000000
--- a/scripts/jailkitupgrade.py
+++ /dev/null
@@ -1,14 +0,0 @@
-"""Update OS components in all Jails"""
-
-def extend(parser):
-    parser.set_defaults(limit='webserver-drupal')
-
-
-def append(args):
-    args.playbook = 'role'
-
-
-def build(cmd, args):
-    cmd.append('--extra-vars=hosts=' + args.limit + ' role=jailkit')
-    cmd.append('--start-at-task=JailKit Role')
-    cmd.append('--tags=UpdateJails')
diff --git a/scripts/jailkituser.py b/scripts/jailkituser.py
deleted file mode 100755
index c0600937..00000000
--- a/scripts/jailkituser.py
+++ /dev/null
@@ -1,16 +0,0 @@
-"""Init and update users in Jails"""
-
-def extend(parser):
-    parser.add_argument('--site', default=None,
-                        help='The id of a site if only one of the defined sites should be updated')
-    parser.set_defaults(limit='webserver-drupal')
-
-
-def append(args):
-    args.playbook = 'user'
-
-
-def build(cmd, args):
-    cmd.append('--tags=JailUserInit,SetPermissions')
-    if args.site:
-        cmd.append('--extra-vars=limit_drupal_site=' + args.site)
diff --git a/scripts/nextcloud.py b/scripts/nextcloud.py
deleted file mode 100755
index 120b7d66..00000000
--- a/scripts/nextcloud.py
+++ /dev/null
@@ -1,14 +0,0 @@
-"""Quickly update NextCloud sites"""
-
-def extend(parser):
-    parser.set_defaults(limit='webserver')
-
-
-def append(args):
-    args.playbook = 'role'
-    args.roles_exclude = 'common,commonauth,commonconnect,commonkeys,apache,php,letsencrypt'
-
-
-def build(cmd, args):
-    cmd.append('--extra-vars=hosts=' + args.limit + ' role=nextcloud')
-    cmd.append('--tags=deploy')
diff --git a/scripts/nextcloud.yml b/scripts/nextcloud.yml
new file mode 100644
index 00000000..38beff1d
--- /dev/null
+++ b/scripts/nextcloud.yml
@@ -0,0 +1,21 @@
+description: 'Quickly update NextCloud sites'
+cli:
+  defaults:
+    limit: 'webserver'
+arguments:
+  playbook: 'role'
+  roles_exclude:
+    - 'common'
+    - 'commonauth'
+    - 'commonconnect'
+    - 'commonkeys'
+    - 'apache'
+    - 'php'
+    - 'letsencrypt'
+command:
+  - name: 'tags'
+    value: 'deploy'
+  - name: 'extra-vars'
+    value: 'hosts=%s role=nextcloud'
+    args:
+      - 'limit'
diff --git a/scripts/piwik.py b/scripts/piwik.py
deleted file mode 100755
index 60c9ec7a..00000000
--- a/scripts/piwik.py
+++ /dev/null
@@ -1,14 +0,0 @@
-"""Quickly update Piwik sites"""
-
-def extend(parser):
-    parser.set_defaults(limit='piwikserver')
-
-
-def append(args):
-    args.playbook = 'role'
-    args.roles_exclude = 'common,commonauth,commonconnect,commonkeys,apache,php,letsencrypt'
-
-
-def build(cmd, args):
-    cmd.append('--extra-vars=hosts=' + args.limit + ' role=piwik')
-    cmd.append('--tags=deploy')
diff --git a/scripts/piwik.yml b/scripts/piwik.yml
new file mode 100644
index 00000000..e31ef6a3
--- /dev/null
+++ b/scripts/piwik.yml
@@ -0,0 +1,21 @@
+description: 'Quickly update Piwik sites'
+cli:
+  defaults:
+    limit: 'piwikserver'
+arguments:
+  playbook: 'role'
+  roles_exclude:
+    - 'common'
+    - 'commonauth'
+    - 'commonconnect'
+    - 'commonkeys'
+    - 'apache'
+    - 'php'
+    - 'letsencrypt'
+command:
+  - name: 'tags'
+    value: 'deploy'
+  - name: 'extra-vars'
+    value: 'hosts=%s role=piwik'
+    args:
+      - 'limit'
diff --git a/scripts/role.py b/scripts/role.py
deleted file mode 100755
index 328dd5d5..00000000
--- a/scripts/role.py
+++ /dev/null
@@ -1,15 +0,0 @@
-"""Run a specific role only"""
-
-def extend(parser):
-    parser.add_argument('role',
-                        help='Role to execute')
-    parser.add_argument('hosts',
-                        help='Host name or pattern')
-
-
-def append(args):
-    args.playbook = 'role'
-
-
-def build(cmd, args):
-    cmd.append('--extra-vars=hosts=' + args.hosts + ' role=' + args.role)
diff --git a/scripts/role.yml b/scripts/role.yml
new file mode 100644
index 00000000..ba955281
--- /dev/null
+++ b/scripts/role.yml
@@ -0,0 +1,15 @@
+description: 'Run a specific role only'
+cli:
+  arguments:
+    role:
+      help: 'Role to execute'
+    hosts:
+      help: 'Host name or pattern'
+arguments:
+  playbook: 'role'
+command:
+  - name: 'extra-vars'
+    value: 'hosts=%s role=%s'
+    args:
+      - 'hosts'
+      - 'role'
diff --git a/scripts/sanity.py b/scripts/sanity.py
deleted file mode 100755
index 5fadbc99..00000000
--- a/scripts/sanity.py
+++ /dev/null
@@ -1,17 +0,0 @@
-"""Check for updates, upgrade and reboot hosts"""
-
-def extend(parser):
-    parser.add_argument('mode', choices=['check', 'upgrade', 'reboot'],
-                        help='Mode for the sanity play')
-    parser.add_argument('--force', action='store_true', default=False,
-                        help='Force to also reboot proxy servers')
-
-
-def append(args):
-    args.playbook = 'sanity'
-
-
-def build(cmd, args):
-    cmd.append('--tags=' + args.mode)
-    if args.force:
-        cmd.append('--extra-vars=force=true')
diff --git a/scripts/sanity.yml b/scripts/sanity.yml
new file mode 100644
index 00000000..2e1a51ea
--- /dev/null
+++ b/scripts/sanity.yml
@@ -0,0 +1,24 @@
+description: 'Check for updates, upgrade and reboot hosts'
+cli:
+  arguments:
+    mode:
+      choices:
+        - 'check'
+        - 'upgrade'
+        - 'reboot'
+      help: 'Mode for the sanity play'
+  options:
+    force:
+      action: 'store_true'
+      default: False
+      help: 'Force to also reboot proxy servers'
+arguments:
+  playbook: 'sanity'
+command:
+  - name: 'tags'
+    value: '%s'
+    args:
+      - 'mode'
+  - name: 'extra-vars'
+    condition: 'force'
+    value: 'force=true'
diff --git a/scripts/shells.py b/scripts/shells.py
deleted file mode 100755
index 961505c1..00000000
--- a/scripts/shells.py
+++ /dev/null
@@ -1,13 +0,0 @@
-"""Build SSL Certs for HaProxy"""
-
-def extend(parser):
-    pass
-
-
-def append(args):
-    args.playbook = 'farm'
-    args.roles_exclude = 'drupal,drupal-cli,drupalconsole,drush,composer,apache,php,redis,memcache,letsencrypt'
-
-
-def build(cmd, args):
-    cmd.append('--tags=shells')
diff --git a/scripts/shells.yml b/scripts/shells.yml
new file mode 100644
index 00000000..534f8a78
--- /dev/null
+++ b/scripts/shells.yml
@@ -0,0 +1,17 @@
+description: 'Build SSL Certs for HaProxy'
+arguments:
+  playbook: 'farm'
+  roles_exclude:
+    - 'drupal'
+    - 'drupal-cli'
+    - 'drupalconsole'
+    - 'drush'
+    - 'composer'
+    - 'apache'
+    - 'php'
+    - 'redis'
+    - 'memcache'
+    - 'letsencrypt'
+command:
+  - name: 'tags'
+    value: 'shells'
diff --git a/scripts/users.py b/scripts/users.py
deleted file mode 100755
index f3b99475..00000000
--- a/scripts/users.py
+++ /dev/null
@@ -1,15 +0,0 @@
-"""Create and configure all users
-
-Notice: this is NOT going through jails and other roles, just the users themselves
-"""
-
-def extend(parser):
-    parser.set_defaults(limit='all')
-
-
-def append(args):
-    args.playbook = 'role'
-
-
-def build(cmd, args):
-    cmd.append('--extra-vars=hosts=' + args.limit + ' role=commonauth')
diff --git a/scripts/users.yml b/scripts/users.yml
new file mode 100644
index 00000000..f56df15d
--- /dev/null
+++ b/scripts/users.yml
@@ -0,0 +1,12 @@
+description: 'Create and configure all users'
+note: 'this is NOT going through jails and other roles, just the users themselves'
+cli:
+  defaults:
+    limit: 'all'
+arguments:
+  playbook: 'role'
+command:
+  - name: 'extra-vars'
+    value: 'hosts=%s role=commonauth'
+    args:
+      - 'limit'
diff --git a/scripts/varnish-config.yml b/scripts/varnish-config.yml
new file mode 100644
index 00000000..a2160f43
--- /dev/null
+++ b/scripts/varnish-config.yml
@@ -0,0 +1,13 @@
+description: 'Quickly configure Varnish'
+cli:
+  defaults:
+    limit: 'varnishserver'
+arguments:
+  playbook: 'role'
+command:
+  - name: 'tags'
+    value: 'Config'
+  - name: 'extra-vars'
+    value: 'hosts=%s role=varnish'
+    args:
+      - 'limit'
diff --git a/scripts/varnishconfig.py b/scripts/varnishconfig.py
deleted file mode 100755
index faa58a03..00000000
--- a/scripts/varnishconfig.py
+++ /dev/null
@@ -1,13 +0,0 @@
-"""Quickly configure Varnish"""
-
-def extend(parser):
-    parser.set_defaults(limit='varnishserver')
-
-
-def append(args):
-    args.playbook = 'role'
-
-
-def build(cmd, args):
-    cmd.append('--tags=Config')
-    cmd.append('--extra-vars=hosts=' + args.limit + ' role=varnish')
diff --git a/scripts/youtrack.py b/scripts/youtrack.py
deleted file mode 100755
index 4bfce78e..00000000
--- a/scripts/youtrack.py
+++ /dev/null
@@ -1,13 +0,0 @@
-"""Quickly update YouTrack sites"""
-
-def extend(parser):
-    parser.set_defaults(limit='youtrackserver')
-
-
-def append(args):
-    args.playbook = 'role'
-    args.roles_exclude = 'common,commonauth,commonconnect,commonkeys,apache,php'
-
-
-def build(cmd, args):
-    cmd.append('--extra-vars=hosts=' + args.limit + ' role=youtrack')
diff --git a/scripts/youtrack.yml b/scripts/youtrack.yml
new file mode 100644
index 00000000..9d338119
--- /dev/null
+++ b/scripts/youtrack.yml
@@ -0,0 +1,18 @@
+description: 'Quickly update YouTrack sites'
+cli:
+  defaults:
+    limit: 'youtrackserver'
+arguments:
+  playbook: 'role'
+  roles_exclude:
+    - 'common'
+    - 'commonauth'
+    - 'commonconnect'
+    - 'commonkeys'
+    - 'apache'
+    - 'php'
+command:
+  - name: 'extra-vars'
+    value: 'hosts=%s role=outrack'
+    args:
+      - 'limit'
diff --git a/wiki b/wiki
index 26edcebc..02269052 160000
--- a/wiki
+++ b/wiki
@@ -1 +1 @@
-Subproject commit 26edcebc00a18d2dafde278ccfdedc20c4ca63a6
+Subproject commit 0226905216d52ec0c7dac3804a5cbbc50e503f9e
-- 
GitLab