From 10f8ca40126f12acc6ab4ef9be07d558a34098b7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rg=20Sachse?= <joerg.sachse@slub-dresden.de>
Date: Thu, 10 Nov 2022 11:32:47 +0100
Subject: [PATCH] chore: migrate to universally used Vagrant/VBox based
 Molecule testsuite from molecule-skel

---
 .ansible-lint                                 |  45 +++--
 .gitignore                                    |  14 +-
 .gitlab-ci.yml                                |  67 +++-----
 ci-ansible.cfg                                |  65 -------
 ci-playbook.yml                               |  21 ---
 molecule/README.md                            | 139 ++++++++-------
 molecule/default                              |   1 +
 molecule/default/converge.yml                 |   5 -
 molecule/default/molecule.yml                 |  36 ----
 molecule/default/prepare.yml                  |  40 -----
 molecule/default/tests/conftest.py            |  20 ---
 molecule/default/tests/test_default.py        | 159 ------------------
 .../playbooks}/INSTALL.rst                    |   6 +-
 molecule/resources/playbooks/README.md        |   3 +
 molecule/resources/playbooks/converge.yml     |  17 ++
 molecule/resources/playbooks/prepare.yml      |  53 ++++++
 molecule/resources/playbooks/verify.yml       |  10 ++
 molecule/virtualbox/molecule.yml              |  41 +++++
 requirements.yml                              |  12 --
 19 files changed, 263 insertions(+), 491 deletions(-)
 delete mode 100644 ci-ansible.cfg
 delete mode 100644 ci-playbook.yml
 create mode 120000 molecule/default
 delete mode 100644 molecule/default/converge.yml
 delete mode 100644 molecule/default/molecule.yml
 delete mode 100644 molecule/default/prepare.yml
 delete mode 100644 molecule/default/tests/conftest.py
 delete mode 100644 molecule/default/tests/test_default.py
 rename molecule/{default => resources/playbooks}/INSTALL.rst (84%)
 create mode 100644 molecule/resources/playbooks/README.md
 create mode 100644 molecule/resources/playbooks/converge.yml
 create mode 100644 molecule/resources/playbooks/prepare.yml
 create mode 100644 molecule/resources/playbooks/verify.yml
 create mode 100644 molecule/virtualbox/molecule.yml
 delete mode 100644 requirements.yml

diff --git a/.ansible-lint b/.ansible-lint
index 9c9323e..f18a647 100644
--- a/.ansible-lint
+++ b/.ansible-lint
@@ -6,7 +6,7 @@
 # and not relative to the CWD of execution. CLI arguments passed to the --exclude
 # option will be parsed relative to the CWD of execution.
 exclude_paths:
-  - .cache/ # implicit unless exclude_paths is defined in config
+  - .cache/    # implicit unless exclude_paths is defined in config
   - .git/
   - .githooks/
   - backups/
@@ -15,24 +15,19 @@ exclude_paths:
 # verbosity: 1
 
 # Mock modules or roles in order to pass ansible-playbook --syntax-check
-#mock_modules:
-#  - zuul_return
-#  # note the foo.bar is invalid as being neither a module or a collection
-#  - fake_namespace.fake_collection.fake_module
-#  - fake_namespace.fake_collection.fake_module.fake_submodule
-#mock_roles:
-#  - mocked_role
-#  - author.role_name # old standalone galaxy role
-#  - fake_namespace.fake_collection.fake_role # role within a collection
+# mock_modules:
+#   - zuul_return
+#   # note the foo.bar is invalid as being neither a module or a collection
+#   - fake_namespace.fake_collection.fake_module
+#   - fake_namespace.fake_collection.fake_module.fake_submodule
+# mock_roles:
+#   - mocked_role
+#   - author.role_name # old standalone galaxy role
+#   - fake_namespace.fake_collection.fake_role # role within a collection
 
 # Enable checking of loop variable prefixes in roles
 loop_var_prefix: "{role}_"
 
-# Enforce variable names to follow pattern below, in addition to Ansible own
-# requirements, like avoiding python identifiers. To disable add `var-naming`
-# to skip_list.
-var_naming_pattern: "^[a-z_][a-z0-9_]*$"
-
 use_default_rules: true
 # Load custom rules from this specific folder
 # rulesdir:
@@ -46,9 +41,9 @@ skip_list:
 # Any rule that has the 'opt-in' tag will not be loaded unless its 'id' is
 # mentioned in the enable_list:
 enable_list:
-  - empty-string-compare # opt-in
-  - no-log-password # opt-in
-  - no-same-owner # opt-in
+  - empty-string-compare    # opt-in
+  - no-log-password         # opt-in
+  - no-same-owner           # opt-in
   # add yaml here if you want to avoid ignoring yaml checks when yamllint
   # library is missing. Normally its absence just skips using that rule.
   - yaml
@@ -60,19 +55,19 @@ enable_list:
 warn_list:
   - skip_this_tag
   - git-latest
-  - experimental # experimental is included in the implicit list
+  - experimental    # experimental is included in the implicit list
   # - role-name
 
 # Offline mode disables installation of requirements.yml
 offline: false
 
 # Define required Ansible's variables to satisfy syntax check
-#extra_vars:
-#  foo: bar
-#  multiline_string_variable: |
-#    line1
-#    line2
-#  complex_variable: ":{;\t$()"
+# extra_vars:
+#   foo: bar
+#   multiline_string_variable: |
+#     line1
+#     line2
+#   complex_variable: ":{;\t$()"
 
 # Uncomment to enforce action validation with tasks, usually is not
 # needed as Ansible syntax check also covers it.
diff --git a/.gitignore b/.gitignore
index 76ea473..b359c28 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,6 @@
 # Compiled source #
 ###################
 *.bin
-*.com
 *.class
 *.dll
 *.exe
@@ -51,6 +50,8 @@ Thumbs.db
 
 *.retry
 *.vault
+inventory.*
+inv.*
 
 # Vim #
 #######
@@ -73,7 +74,14 @@ tags
 .vagrant/
 *.box
 
-# MISC #
-########
+# Temporary/Build/Backup #
+##########################
 
 backups/
+build/
+
+# CONFIDENTIAL #
+################
+
+ssh_host_*
+
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 826ac6e..7174cad 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,56 +1,35 @@
-# This file is a template, and might need editing before it works on your project.
-# To contribute improvements to CI/CD templates, please follow the Development guide at:
-# https://docs.gitlab.com/ee/development/cicd/templates.html
-# This specific template is located at:
-# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Getting-Started.gitlab-ci.yml
-
-# This is a sample GitLab CI/CD configuration file that should run without any modifications.
-# It demonstrates a basic 3 stage CI/CD pipeline. Instead of real tests or scripts,
-# it uses echo commands to simulate the pipeline execution.
-#
+---
 # A pipeline is composed of independent jobs that run scripts, grouped into stages.
 # Stages run in sequential order, but jobs within stages run in parallel.
 #
 # For more information, see: https://docs.gitlab.com/ee/ci/yaml/index.html#stages
 
 stages:          # List of stages for jobs, and their order of execution
-  - build
   - test
 
-variables:
-  IMAGE_TARGET: "$CI_REGISTRY_IMAGE/bullseye_subapp"
-#  CI_DEBUG_TRACE: "true"
-
 default:
-  image:
-    name: "${IMAGE_TARGET}:latest"
+  before_script:
+    - source /opt/molecule/bin/activate
+    - ansible --version
+    - molecule --version
+  after_script:
+    - source /opt/molecule/bin/activate
+    - molecule destroy --scenario-name default
 
-build-env-job:       # This job runs in the build stage, which runs first.
-  stage: build
-  timeout: 30m
+test-job:
+  stage: test
   tags:
-    - "docker"
-  image:
-    name: gcr.io/kaniko-project/executor:debug
-    entrypoint: [""]
-  before_script: []
-  script:
-    - mkdir -p /kaniko/.docker
-    - echo "{\"auths\":{\"$CI_REGISTRY\":{\"auth\":\"$(printf "%s:%s" "$CI_REGISTRY_USER" "$CI_REGISTRY_PASSWORD" | base64 | tr -d '\n')\"},\"$(printf "%s" "$CI_DEPENDENCY_PROXY_SERVER" | cut -d':' -f1)\":{\"auth\":\"$(printf "%s:%s" "$CI_DEPENDENCY_PROXY_USER" "$CI_DEPENDENCY_PROXY_PASSWORD" | base64 | tr -d '\n')\"}}}" > /kaniko/.docker/config.json
-    - >-
-      /kaniko/executor
-      --context "${CI_PROJECT_DIR}"
-      --dockerfile "${CI_PROJECT_DIR}/tests/Dockerfile"
-      --destination "${IMAGE_TARGET}:latest"
-
-unit-test-job:   # This job runs in the test stage.
-  stage: test    # It only starts when the job in the build stage completes successfully.
+    - "shell"
   script:
-    - sudo chmod o-w /builds/digital-preservation/ansible_lza_repair/
-    - echo "${VAULT_INSTALL_COMMON}" > /builds/digital-preservation/lza_install_common.pass
-    - echo "${VAULT_SERVER_HARDENING}" > /builds/digital-preservation/lza_server_hardening.pass
-    - echo "${VAULT_REPAIR}" > /builds/digital-preservation/lza_repair.pass
-    - echo "${VAULT_OSQUERY}" > /builds/digital-preservation/slub_osquery.pass
-    - rm -rf /builds/digital-preservation/ansible_vaults/
-    - git clone https://gitlab+deploy-token-25:${VAULT_ACCESS_TOKEN}@git.slub-dresden.de/slub-referat-2-3/ansible_vaults.git /builds/digital-preservation/ansible_vaults/
-    - ansible-playbook --user "lza" --become --tags ci /builds/digital-preservation/ansible_lza_repair/ci-playbook.yml
+    # make sure that Ansible Vaults are present and can be decrypted
+    - echo "${VAULT_REPAIR}" > ../lza_repair.pass
+    - export ANSIBLE_VAULT_IDENTITY_LIST="../lza_repair.pass"
+    - rm -rf ../ansible_vaults/
+    - git clone https://gitlab+deploy-token-25:${VAULT_ACCESS_TOKEN}@git.slub-dresden.de/slub-referat-2-3/ansible_vaults.git ../ansible_vaults/; \
+    # run Molecule tests
+    - molecule syntax --scenario-name default
+    - molecule lint --scenario-name default
+    - molecule create --scenario-name default
+    - molecule converge --scenario-name default
+    - molecule idempotence --scenario-name default
+    # - molecule verify --scenario-name default
diff --git a/ci-ansible.cfg b/ci-ansible.cfg
deleted file mode 100644
index 6a8b72b..0000000
--- a/ci-ansible.cfg
+++ /dev/null
@@ -1,65 +0,0 @@
-[defaults]
-# If set, configures the path to the Vault password file as an alternative to
-# specifying --vault-password-file on the command line.
-#vault_identity_list = ../lza_install_common.pass, ../lza_server_hardening.pass, ../lza_repair.pass, ../slub_osquery.pass
-
-# Path to default inventory file
-# Administrators can override this by using the "-i <inventoryfile>" CLI
-# argument.
-inventory           = ./inv.ini
-
-# Remote user name
-# We DELIBERATELY set this to an non-existent non-root username to make sure
-# the role can only be run if an Administrator knows the correct remote_user
-# name and passes it as a CLI argument.
-remote_user         = non-root-user
-
-# By default, ansible will use the 'linear' strategy but you may want to try
-# another one
-strategy            = free
-
-# Don't like cows?  that's unfortunate.
-# Set to 1 if you don't want cowsay support or export ANSIBLE_NOCOWS=1
-nocows = 1
-
-# Custom role path that guarantees roles are always found, no matter where a
-# user checks them out.
-roles_path = /tmp/:./:../:~/.ansible/roles:/usr/share/ansible/roles:/etc/ansible/roles
-
-# Toggle to control displaying skipped task/host entries in a task in the
-# default callback.
-# https://docs.ansible.com/ansible/latest/reference_appendices/config.html#display-skipped-hosts
-# DEFAULT: display_skipped_hosts = true
-display_skipped_hosts = false
-
-use_persistent_connections=true
-
-# list all Ansible Callback Plugins: "ansible-doc -t callback -l"
-# online documentation: https://docs.ansible.com/ansible/latest/plugins/callback.html
-# run code profiling for performance analysis
-# callbacks_enabled = profile_roles, profile_tasks, timer
-# get formatted output
-# callbacks_enabled = yaml
-# get minimal output
-# callbacks_enabled = dense
-
-# set default output callback plugin
-stdout_callback = yaml
-
-# Setting a callback plugin for ad-hoc commands
-bin_ansible_callbacks = True
-
-callbacks_enabled: yaml
-
-[inventory]
-# Ignore these extensions when parsing a directory as inventory source.
-ignore_extensions = .pyc, .pyo, .swp, .bak, ~, .rpm, .md, .txt, ~, .orig, .ini, .cfg, .retry
-
-[ssh_connection]
-# Enabling pipelining reduces the number of SSH operations required to
-# execute a module on the remote server. This can result in a significant
-# performance improvement when enabled, however when using "sudo:" you must
-# first disable 'requiretty' in /etc/sudoers
-# By default, this option is disabled to preserve compatibility with
-# sudoers configurations that have requiretty (the default on many distros).
-pipelining = True
diff --git a/ci-playbook.yml b/ci-playbook.yml
deleted file mode 100644
index 34324ca..0000000
--- a/ci-playbook.yml
+++ /dev/null
@@ -1,21 +0,0 @@
----
-- hosts: "localhost"
-  connection: local
-  # Collect facts from remote system? Possible values: true, false
-  gather_facts: true
-  # any_error_fatal will mark all the hosts as failed if fails and immediately
-  # abort the playbook execution. Possible values: true, false
-  any_errors_fatal: false
-  # max_fail_percentage allows you to abort the play if certain threshold of
-  # failures have been reached.
-  max_fail_percentage: 30
-  serial: 30
-  # hide sensitive information in verbose/debugging output from others.
-  # Possible values: true, false
-  no_log: false
-  # execution strategy, possible values: debug, linear, serial, free
-  # https://docs.ansible.com/ansible/latest/user_guide/playbooks_strategies.html
-  strategy: linear
-
-  roles:
-    - {role: ansible_lza_repair, become: true}
diff --git a/molecule/README.md b/molecule/README.md
index 33a7eb5..fdb41fe 100644
--- a/molecule/README.md
+++ b/molecule/README.md
@@ -4,39 +4,53 @@
 
 In order to be able to use the tests, you need to have some software packages installed. You may need sudo privileges for some of these operations.
 
-        ### install VirtualBox
-        # do NOT use distribution packages
-        # process documented at https://www.virtualbox.org/wiki/Linux_Downloads
-        #
-        # add repository URL
-        sudo echo "deb [arch=amd64] https://download.virtualbox.org/virtualbox/debian stretch contrib" > /etc/apt/sources.d/virtualbox.list
-        # add GPG key
-        wget -q https://www.virtualbox.org/download/oracle_vbox.asc -O- | sudo apt-key add -
-        # update sources
-        sudo apt update
-        # install VirtualBox
-        sudo apt-get install virtualbox-6.1
-
-        ### install Vagrant
-        # do NOT use distribution packages
-        # 
-        # download Debian package from Hashicorp
-        wget https://releases.hashicorp.com/vagrant/2.2.9/vagrant_2.2.9_x86_64.deb
-        # install package
-        sudo dpkg -i vagrant_2.2.9_x86_64.deb
-
-        ### install Molecule et. al.
-        # prepare directories
-        mkdir ~/python-envs/ && cd ~/python-env/
-        # create Python Virtual Environment with Python3 interpreter (Python2 is deprecated!)
-        virtualenv -p python3 molecule-env
-        # enter the Virtual Environment in your current shell (other shells will be unaffected)
-        source molecule-env/bin/activate
-        # install packages
-        pip3 install molecule ansible testinfra ansible-lint molecule-vagrant molecule-docker
-
-        # leave the Virtual Environment only when you're done
-        deactivate
+There are two ways to accomplish this.
+
+### Option 1: use `molecule-skel` (SLUB staff only)
+
+1. Clone the project at [molecule-skel](https://git.slub-dresden.de/slub-referat-2-3/molecule-skel): `git clone https://git.slub-dresden.de/slub-referat-2-3/molecule-skel.git`
+2. Switch to the `molecule-skel` repository directory and run `./install_testenv.sh`.
+3. PROFIT!
+
+ Check the `README.md` over at [molecule-skel](https://git.slub-dresden.de/slub-referat-2-3/molecule-skel) for details on how to use that. It's easy, I promise.
+
+### Option 2: manual installation
+
+Run these steps on your terminal.
+
+```bash
+### install VirtualBox
+# do NOT use distribution packages, as they may be too old!
+# process documented at https://www.virtualbox.org/wiki/Linux_Downloads
+#
+# add GPG key
+wget -q https://www.virtualbox.org/download/oracle_vbox.asc -O- | sudo apt-key add -
+# add repository URL
+sudo echo "deb [arch=amd64] https://download.virtualbox.org/virtualbox/debian stretch contrib" > /etc/apt/sources.d/virtualbox.list
+# update sources and install VirtualBox
+sudo apt update; sudo apt-get install virtualbox-6.1
+
+### install Vagrant
+# do NOT use distribution packages, as they may be too old!
+# 
+# download Debian package from Hashicorp
+wget https://releases.hashicorp.com/vagrant/2.2.9/vagrant_2.2.9_x86_64.deb
+# install package
+sudo dpkg -i vagrant_2.2.9_x86_64.deb
+
+### install Molecule et. al.
+# prepare directories
+mkdir ~/python-envs/ && cd ~/python-env/
+# create Python Virtual Environment with Python3 interpreter (Python2 is deprecated!)
+virtualenv -p python3 molecule-env
+# enter the Virtual Environment in your current shell (other shells will be unaffected)
+source molecule-env/bin/activate
+# install packages
+pip3 install molecule ansible testinfra ansible-lint molecule-vagrant molecule-docker
+
+# leave the Virtual Environment only when you're done
+deactivate
+```
 
 You can find suitable documentation at the respective vendors' websites.
 * [Vagrant Installation Guide](https://www.vagrantup.com/docs/installation/)
@@ -46,10 +60,14 @@ You can find suitable documentation at the respective vendors' websites.
 ## Initialising a new Molecule scenario
 
 If you have already created a role without the Molecule test framework or you want to add test scenarios, you can use:
-	molecule init scenario --scenario-name <my_scenario> --driver [azure|delegated|docker|ec2|gce|linode|lxc|lxd|openstack|vagrant] --verifier-name [ansible|testinfra]
+```bash
+molecule init scenario --scenario-name <my_scenario> --driver [azure|delegated|docker|ec2|gce|linode|lxc|lxd|openstack|vagrant] --verifier-name [ansible|testinfra]
+```
 
 If you need any help with the options, please use:
-	molecule init role --help
+```bash
+molecule init role --help
+```
 
 ## Running Tests
 
@@ -60,26 +78,31 @@ Various test environments are separated into so-called "scenarios" that can be b
 In the simplest configuration, the `molecule/` directory only contains one `default/` directory that contains the default scenario. This scenario is run if no other scenario is chosen using the `-s` CLI option.
 
 This is the basic usage of Molecule:
-	# create test infrastructure
-	cd <role_directory>
-	molecule create
-	# run playbooks against test infrastructure
-	molecule converge
-	# run Testinfra tests
-	molecule verify
-	# remove test infrastructure
-	molecule destroy
-
-	# run all steps at once:
-	molecule test
-
-It has proven helpful to use Vagrant to create a snapshot of the VM after the creation phase has completed.
-	# First, get UUID of the VM
-	vagrant global-status
-	# Then, create the snapshot
-	vagrant snapshot save <uuid> <snapshot_name>
-	# To restore the snapshot, use
-	vagrant snapshot restore <uuid> <snapshot_name>
-	# And to remove the snapshot, use
-	vagrant snapshot delete <uuid> <snapshot_name>
-
+```bash
+# create test infrastructure
+cd <role_directory>
+molecule create
+# run playbooks against test infrastructure
+molecule converge
+# run idempotence tests
+molecule idempotence
+# run tests, if they exist
+molecule verify
+# remove test infrastructure
+molecule destroy
+
+# run all steps at once:
+molecule test
+```
+
+It has proven helpful to use Vagrant to create a snapshot of the VM after the creation phase has completed. Just like this:
+```bash
+# First, get UUID of the VM
+vagrant global-status
+# Then, create the snapshot
+vagrant snapshot save <uuid> <snapshot_name>
+# To restore the snapshot, use
+vagrant snapshot restore <uuid> <snapshot_name>
+# And to remove the snapshot, use
+vagrant snapshot delete <uuid> <snapshot_name>
+```
diff --git a/molecule/default b/molecule/default
new file mode 120000
index 0000000..3841ab1
--- /dev/null
+++ b/molecule/default
@@ -0,0 +1 @@
+./virtualbox
\ No newline at end of file
diff --git a/molecule/default/converge.yml b/molecule/default/converge.yml
deleted file mode 100644
index f968d69..0000000
--- a/molecule/default/converge.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-- name: Converge
-  hosts: all
-  roles:
-    - {role: "ansible_lza_repair", become: true}
diff --git a/molecule/default/molecule.yml b/molecule/default/molecule.yml
deleted file mode 100644
index 7d5e17a..0000000
--- a/molecule/default/molecule.yml
+++ /dev/null
@@ -1,36 +0,0 @@
----
-dependency:
-  name: galaxy
-driver:
-  name: vagrant
-  provider:
-    name: virtualbox
-lint: |
-  set -e
-  yamllint .
-  ansible-lint -x formatting
-  flake8 --ignore=E501
-platforms:
-  - name: molecule-lza-repair
-    box: debian/buster64
-    memory: 512
-    cpus: 1
-provisioner:
-  name: ansible
-  log: true
-  config_options:
-    defaults:
-      vault_identity_list: "@$HOME/.ansible/roles/molecule_prepare.pass, @$HOME/.ansible/roles/lza_install_common.pass, @$HOME/.ansible/roles/lza_server_hardening.pass, @$HOME/.ansible/roles/lza_repair.pass"
-  lint:
-    name: ansible-lint
-    enabled: false
-  vvv: false
-verifier:
-  name: testinfra
-  env:
-    PYTHONWARNINGS: "ignore:.*U.*mode is deprecated:DeprecationWarning"
-  lint: |
-    set -e
-    flake8
-  options:
-    v: 1
diff --git a/molecule/default/prepare.yml b/molecule/default/prepare.yml
deleted file mode 100644
index d903f56..0000000
--- a/molecule/default/prepare.yml
+++ /dev/null
@@ -1,40 +0,0 @@
----
-- name: Prepare
-  hosts: all
-  gather_facts: true
-  pre_tasks:
-    - name: include vars
-      include_vars: "../../../ansible_vaults/molecule_prepare/{{ item }}"
-      loop:
-        - "prepare.vault"
-    - name: Install python for Ansible
-      raw: test -e /usr/bin/python || (apt -y update && apt install -y python-minimal)
-      become: true
-      changed_when: false
-    - name: create users (as deployed in production)
-      user:
-        name: "{{ item.name }}"
-        uid: "{{ item.uid }}"
-        create_home: "yes"
-        shell: "/bin/bash"
-      loop: "{{ vault_molecule_users | flatten(levels=1) }}"
-      become: true
-    - name: add nonfree repos
-      apt_repository:
-        repo: "deb http://ftp2.de.debian.org/debian/ buster main non-free contrib"
-        state: present
-        update-cache: "yes"
-      become: true
-    - name: Install required packages
-      apt:
-        name: [
-          'aptitude',
-          'gpg',
-          'less',
-          'libuser'
-        ]
-        state: present
-      become: true
-  roles:
-    - {role: ansible_lza_install_common, become: true}
-    - {role: ansible_lza_server_hardening, become: true}
diff --git a/molecule/default/tests/conftest.py b/molecule/default/tests/conftest.py
deleted file mode 100644
index ba0f1e8..0000000
--- a/molecule/default/tests/conftest.py
+++ /dev/null
@@ -1,20 +0,0 @@
-"""PyTest Fixtures."""
-from __future__ import absolute_import
-import os
-import pytest
-
-
-def pytest_runtest_setup(item):
-    """Run tests only when under molecule with testinfra installed."""
-    try:
-        import testinfra
-    except ImportError:
-        pytest.skip("Test requires testinfra", allow_module_level=True)
-    if "MOLECULE_INVENTORY_FILE" in os.environ:
-        pytest.testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
-            os.environ["MOLECULE_INVENTORY_FILE"]
-        ).get_hosts("all")
-    else:
-        pytest.skip(
-            "Test should run only from inside molecule.", allow_module_level=True
-        )
diff --git a/molecule/default/tests/test_default.py b/molecule/default/tests/test_default.py
deleted file mode 100644
index 45f4f67..0000000
--- a/molecule/default/tests/test_default.py
+++ /dev/null
@@ -1,159 +0,0 @@
-# import os
-# import testinfra
-
-
-def test_hosts_file(host):
-    f = host.file('/etc/hosts')
-
-    assert f.exists
-    assert f.user == 'root'
-    assert f.group == 'root'
-
-
-def test_etc_systemd_user_repair_daemon_ddz_service(host):
-    f = host.file('/etc/systemd/user/repair_daemon_ddz.service')
-    assert f.exists
-    assert f.user == 'root'
-    assert f.group == 'root'
-    assert f.mode == 0o400
-
-
-def test_etc_systemd_user_repair_daemon_digas_service(host):
-    f = host.file('/etc/systemd/user/repair_daemon_digas.service')
-    assert f.exists
-    assert f.user == 'root'
-    assert f.group == 'root'
-    assert f.mode == 0o400
-
-
-# Tests for install-packages.yml
-def test_packages_installed(host):
-    packages = [
-        'libtiff-tools',
-        'logrotate',
-        'lsb-release',
-        'nfs-common',
-        'perl',
-        'perl-base',
-        'perl-modules-5.28',
-        'rsync',
-        'samba',
-        'samba-common',
-        'tar',
-        'unzip'
-    ]
-    for item in packages:
-        package = host.package(item)
-        assert package.is_installed
-
-
-# Tests for create-users-groups.yml
-def test_create_users_groups(host):
-    groups = [['exlibris', 500], ['aw_lza_repair', 1003]]
-    for item in groups:
-        group = host.group(item[0])
-        assert group.exists is True
-        assert group.gid == item[1]
-
-    u = host.user("lza")
-    assert u.group == 'exlibris'
-    assert u.groups.sort() == ['lza', 'sudo', 'exlibris', 'aw_lza_repair'].sort()
-
-
-# Tests for configure-nfs-mounts.yml
-def test_configure_nfs_mounts(host):
-    # hostname = str(os.uname().nodename)
-    # print("'{hostname}'")
-    mountpoints = [
-        [f"/var/log/repair/molecule-lza-repair/", "212.201.62.107:/vol/linux_server_logs/{hostname}"],
-        ["/mnt/lza_repair_ddz/", "212.201.62.107:/vol/lza_repair_stack"],
-        ["/mnt/lza_repair_digas/", "212.201.62.107:/vol/lza_repair_stack_digas"]
-    ]
-    for item in mountpoints:
-        # mp = host.mount_point(item[0])
-        d = host.file(item[0])
-#        assert mp.exists
-#        assert mp.filesystem == "nfs"
-#        assert mp.device == item[1]
-#        assert mp.options.sort() == ["defaults", "nodev", "nosuid", "rsize=65536", "wsize=65536", "vers=3"]
-        assert d.exists
-        assert d.is_directory is True
-        assert d.user == "lza"
-        assert d.group == "aw_lza_repair"
-        assert d.mode == 0o755
-
-
-# Tests for install-repair-tools.yml
-def test_install_repair_tools(host):
-    dirs = [
-        "/home/lza/.cache/",
-        "/home/lza/.config/repair/bin/",
-        "/home/lza/.config/repair/cfg/"
-    ]
-    for item in dirs:
-        with host.sudo():
-            d = host.file(item)
-            assert d.exists
-            assert d.is_directory is True
-            assert d.user == "lza"
-            assert d.group == "lza"
-            assert d.mode == 0o755
-
-    package = host.package("libslub-lza-repair-perl")
-    assert package.is_installed
-
-    repair_tools = [
-        ["/usr/local/bin/checkit_tiff", 0o700],
-        ["/etc/cit_tiff6_baseline_SLUB.cfg", 0o600],
-        ["/usr/local/bin/fixit_tiff", 0o700]
-    ]
-    for item in repair_tools:
-        t = host.file(item[0])
-        assert t.exists is True
-        assert t.is_file is True
-        assert t.user == "lza"
-        assert t.group == "lza"
-        assert t.mode == item[1]
-
-    absent_packages = [
-        "git",
-        "make",
-        "cmake",
-        "build-essential",
-        "libpcre3-dev",
-        "libtiff5-dev"
-    ]
-    for item in absent_packages:
-        p = host.package(item)
-        assert p.is_installed is False
-
-    symlinks = [
-        "/home/lza/.config/repair/bin/checkit_tiff",
-        "/home/lza/.config/repair/bin/fixit_tiff",
-        "/home/lza/.config/repair/cfg/cit_tiff6_baseline_SLUB.cfg"
-    ]
-    for item in symlinks:
-        with host.sudo():
-            s = host.file(item)
-            assert s.exists
-            print(item)
-            assert s.is_symlink is True
-
-
-# Tests for configure-systemd-services.yml
-def test_configure_systemd_services(host):
-    units = [
-        "repair_daemon_ddz.service",
-        "repair_daemon_digas.service"
-    ]
-    for item in units:
-        print(f"/etc/systemd/user/{item}")
-        u = host.file(f"/etc/systemd/user/{item}")
-        s = host.service(item)
-        assert u.exists
-        assert u.is_file is True
-        assert u.user == "root"
-        assert u.group == "root"
-        assert u.mode == 0o400
-        assert s.is_enabled is True
-        assert s.is_running is True
diff --git a/molecule/default/INSTALL.rst b/molecule/resources/playbooks/INSTALL.rst
similarity index 84%
rename from molecule/default/INSTALL.rst
rename to molecule/resources/playbooks/INSTALL.rst
index 4f44b67..0c4bf5c 100644
--- a/molecule/default/INSTALL.rst
+++ b/molecule/resources/playbooks/INSTALL.rst
@@ -1,6 +1,6 @@
-*******
+*********************************
 Vagrant driver installation guide
-*******
+*********************************
 
 Requirements
 ============
@@ -20,4 +20,4 @@ widely recommended `'--user' flag`_ when invoking ``pip``.
 
 .. code-block:: bash
 
-    $ pip install 'molecule[vagrant]'
+    $ pip install 'molecule_vagrant'
diff --git a/molecule/resources/playbooks/README.md b/molecule/resources/playbooks/README.md
new file mode 100644
index 0000000..0c91883
--- /dev/null
+++ b/molecule/resources/playbooks/README.md
@@ -0,0 +1,3 @@
+This drectory contains shared playbooks and a shared Dockerfile.
+
+Visit https://molecule.readthedocs.io/en/latest/examples.html#sharing-across-scenarios for details on sharing playbooks, tests etc. across multiple scenarios.
diff --git a/molecule/resources/playbooks/converge.yml b/molecule/resources/playbooks/converge.yml
new file mode 100644
index 0000000..5e9e9df
--- /dev/null
+++ b/molecule/resources/playbooks/converge.yml
@@ -0,0 +1,17 @@
+---
+- name: Converge
+  hosts: all
+  pre_tasks:
+    - name: update apt cache
+      ansible.builtin.apt:
+        update_cache: true
+        upgrade: dist
+      become: true
+      when: ansible_os_family == "Debian"
+    - name: update yum cache
+      ansible.builtin.yum:
+        update_cache: true
+      become: true
+      when: ansible_os_family == "RedHat"
+  roles:
+    - {role: "ansible_lza_repair", become: true}
diff --git a/molecule/resources/playbooks/prepare.yml b/molecule/resources/playbooks/prepare.yml
new file mode 100644
index 0000000..0db49d6
--- /dev/null
+++ b/molecule/resources/playbooks/prepare.yml
@@ -0,0 +1,53 @@
+---
+- name: Prepare
+  hosts: "*"
+  pre_tasks:
+    - name: create group
+      ansible.builtin.group:
+        name: "lza"
+      become: true
+    - name: configure additional package repositories for Debian
+      block:
+        - name: install GPG
+          ansible.builtin.apt:
+            name: "gnupg"
+            state: latest
+            update_cache: true
+          become: true
+        - name: add GPG key for SLUB Debian repository
+          ansible.builtin.apt_key:
+            url: "https://sdvdebianrepo.slub-dresden.de/deb-repository/pub.gpg.key"
+            state: present
+          become: true
+        - name: add repo URL to sources.list
+          ansible.builtin.apt_repository:
+            repo: "deb https://sdvdebianrepo.slub-dresden.de/deb-repository bullseye main"
+            state: present
+            update_cache: true
+            mode: "0644"
+          become: true
+      when: ansible_os_family == "Debian"
+
+    - name: configure additional package repositories for RedHat
+      block:
+        - name: add custom repositories
+          ansible.builtin.yum_repository:
+            name: "{{ item.name }}"
+            description: "{{ item.description }}"
+            baseurl: "{{ item.baseurl }}"
+            gpgcheck: "{{ item.gpgcheck | default('true') }}"
+            gpgkey: "{{ item.gpgkey | default(omit) }}"
+          loop:
+            - name: "epel"
+              description: EPEL YUM repo
+              baseurl: "https://download.fedoraproject.org/pub/epel/{{ ansible_distribution_major_version }}/x86_64/"
+              gpgkey: "https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-{{ ansible_distribution_major_version }}"
+            - name: "slub"
+              description: SLUB YUM repo
+              baseurl: "http://sdvrhelrepo.slub-dresden.de/"
+              gpgcheck: "false"
+        - name: remove legacy repo configuration to avoid double configuration for SLUB repo
+          ansible.builtin.file:
+            path: "/etc/yum.repos.d/SLUB.repo"
+            state: absent
+      when: ansible_os_family == "RedHat"
diff --git a/molecule/resources/playbooks/verify.yml b/molecule/resources/playbooks/verify.yml
new file mode 100644
index 0000000..e707420
--- /dev/null
+++ b/molecule/resources/playbooks/verify.yml
@@ -0,0 +1,10 @@
+---
+# This is an example playbook to execute Ansible tests.
+
+- name: Verify
+  hosts: all
+  gather_facts: false
+  tasks:
+  - name: Example assertion
+    ansible.builtin.assert:
+      that: true
diff --git a/molecule/virtualbox/molecule.yml b/molecule/virtualbox/molecule.yml
new file mode 100644
index 0000000..0a3fa78
--- /dev/null
+++ b/molecule/virtualbox/molecule.yml
@@ -0,0 +1,41 @@
+---
+dependency:
+  name: galaxy
+  enabled: false
+driver:
+  name: vagrant
+lint: |
+  set -e
+  yamllint .
+  ansible-lint -x no-loop-var-prefix,command-instead-of-module,package-latest
+platforms:
+  # Check out the documentation at
+  # https://github.com/ansible-community/molecule-vagrant#documentation
+  # for more platform parameters.
+  - name: vm-runner
+    box: debian/bullseye64
+    memory: 1024
+    # List of raw Vagrant `config` options.
+    # provider_raw_config_args:
+    #   - "customize [ 'modifyvm', :id, '--natdnshostresolver1', 'on' ]"
+    # Dictionary of `config` options.
+    config_options:
+      ssh.keep_alive: true
+      ssh.remote_user: "'lza'"
+provisioner:
+  name: ansible
+  log: true
+  config_options:
+    defaults:
+      # https://stackoverflow.com/questions/57435811/ansible-molecule-pass-multiple-vault-ids
+      # vault_identity_list: "@$HOME/.ansible/roles/lza_install_common.pass, @$HOME/.ansible/roles/passfile_1.pass"
+      vault_identity_list: "../lza_repair.pass"
+  vvv: false
+  playbooks:
+    # create: ../resources/playbooks/create.yml
+    # destroy: ../resources/playbooks/destroy.yml
+    converge: ../resources/playbooks/converge.yml
+    prepare: ../resources/playbooks/prepare.yml
+    verify: ../resources/playbooks/verify.yml
+verifier:
+  name: ansible
diff --git a/requirements.yml b/requirements.yml
deleted file mode 100644
index 58de273..0000000
--- a/requirements.yml
+++ /dev/null
@@ -1,12 +0,0 @@
----
-# https://docs.ansible.com/ansible/latest/galaxy/user_guide.html#installing-multiple-roles-from-a-file
-- src: git+https://git.slub-dresden.de/slub-referat-2-3/ansible_vaults.git
-  scm: git
-- src: git+https://git.slub-dresden.de/digital-preservation/ansible_lza_install_common.git
-  scm: git
-- src: git+https://git.slub-dresden.de/digital-preservation/ansible_lza_server_hardening.git
-  scm: git
-- src: git+https://git.slub-dresden.de/digital-preservation/ansible_slub_osquery.git
-  scm: git
-#- src: git+
-#  scm: git
-- 
GitLab