diff --git a/.github/workflows/molecule.yml b/.github/workflows/molecule.yml new file mode 100644 index 0000000..3b79bb6 --- /dev/null +++ b/.github/workflows/molecule.yml @@ -0,0 +1,100 @@ +--- + +# This is a basic workflow to help you get started with Actions + +name: Molecule + +# Controls when the action will run. Triggers the workflow on push or pull request +# events but only for the master branch +on: + push: + pull_request: + branches: + - master + - tags/* + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + + lint: + # The type of runner that the job will run on + runs-on: ubuntu-latest + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - uses: actions/checkout@v2 + + - name: install lint prerequisite + run: | + sudo apt -y install python3-setuptools ansible-lint + + - name: Install molecule + run: | + sudo apt update + sudo apt -y install python3-setuptools python3 python3-pip docker vagrant + sudo pip3 install wheel + sudo pip3 install docker molecule testinfra yamllint ansible-lint flake8 molecule-vagrant + + - name: molecule lint + run: | + molecule lint + + molecule: + + runs-on: ubuntu-latest + if: "false" + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + - uses: actions/checkout@v2 + + - name: configure keyboard layout + run: | + echo XKBLAYOUT='us' > /etc/default/keyboard + + - name: install virtualization stack + env: + DEBIAN_FRONTEND: noninteractive + run: | + sudo apt-get update + sudo apt -y install cpu-checker + kvm-ok + # shit happens here, containerization sucks... that was worth the try + + - name: install virtualization stack + env: + DEBIAN_FRONTEND: noninteractive + run: | + sudo apt -y install policycoreutils-python-utils qemu-kvm qemu-utils libvirt-clients libvirt-daemon-system bridge-utils python3-libvirt libnss-libvirt libguestfs-tools virtinst virt-top genisoimage libvirt-dev libvirt-bin + + - name: install vagrant + env: + VAGRANT_DISABLE_STRICT_DEPENDENCY_ENFORCEMENT: 1 + run: | + wget https://releases.hashicorp.com/vagrant/2.2.7/vagrant_2.2.7_x86_64.deb + sudo apt -y install ./vagrant_2.2.7_x86_64.deb + vagrant plugin install vagrant-persistent-storage + vagrant plugin install vagrant-libvirt + sudo groupadd --system libvirt + sudo usermod -a -G libvirt $(whoami) + sudo /etc/init.d/libvirtd restart + + - name: Install molecule + run: | + sudo apt -y install python3-setuptools + pip3 install molecule-vagrant wheel + + - name: create molecule vm + env: + LC_ALL: C.UTF-8 + LANG: C.UTF-8 + run: | + molecule create --scenario-name kvm + + - name: verify + run: | + molecule verify + + - name: teardown + run: | + molecule destroy diff --git a/.gitignore b/.gitignore index e69de29..89b745a 100644 --- a/.gitignore +++ b/.gitignore @@ -0,0 +1,2 @@ +.idea +**/__pycache__ \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 291a6b5..3ba4064 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,24 +18,15 @@ env: - distribution: fedora init: /usr/lib/systemd/systemd version: 25 - - distribution: fedora - init: /usr/lib/systemd/systemd - version: 24 - distribution: ubuntu init: /lib/systemd/systemd version: bionic - distribution: ubuntu init: /lib/systemd/systemd version: xenial - - distribution: ubuntu - init: /sbin/init - version: trusty - distribution: debian init: /lib/systemd/systemd version: stretch - - distribution: debian - init: /lib/systemd/systemd - version: jessie before_install: - 'sudo pip install yamllint' diff --git a/molecule/default/converge.yml b/molecule/default/converge.yml new file mode 100644 index 0000000..a3a01f2 --- /dev/null +++ b/molecule/default/converge.yml @@ -0,0 +1,30 @@ +--- +- name: Converge + hosts: all + vars: + lvm_groups: + - vgname: my_vg + disks: + - /dev/sdb1 + create: true + lvnames: + - lvname: my_lv + size: 40%VG + opts: "--wipesignatures y" + create: true + filesystem: ext4 + mount: true + mntp: "/var/lib/mountpoint" + - lvname: my_lv2 + size: 20%VG + opts: "--wipesignatures y" + mount: true + create: true + filesystem: xfs + mntp: "/var/lib/mountpoint2" + manage_lvm: true + + tasks: + - name: "Include lvm" + include_role: + name: "ansible-manage-lvm" diff --git a/molecule/default/molecule.yml b/molecule/default/molecule.yml new file mode 100644 index 0000000..967e97f --- /dev/null +++ b/molecule/default/molecule.yml @@ -0,0 +1,27 @@ +--- +driver: + name: vagrant + provider: + name: virtualbox +lint: yamllint . && flake8 && ansible-lint --exclude=meta +platforms: + - name: Fedora-Molecule-LVM + box: bento/fedora-31 + # box-url: ${platform_root}/packer/bento/builds/fedora-31-x86_64.virtualbox.box + provider_override_args: + - "persistent_storage.enabled = true" + - "persistent_storage.location = 'molecule-lvm.vdi'" + - "persistent_storage.size = 100" + - "persistent_storage.mount = false" + - "persistent_storage.diskdevice = '/dev/sdb'" +provisioner: + name: ansible + inventory: + group_vars: + lvm: +verifier: + name: testinfra + env: + PYTHONWARNINGS: "ignore:.*U.*mode is deprecated:DeprecationWarning" + options: + v: 1 diff --git a/molecule/default/tests/conftest.py b/molecule/default/tests/conftest.py new file mode 100644 index 0000000..7bd2743 --- /dev/null +++ b/molecule/default/tests/conftest.py @@ -0,0 +1,21 @@ +"""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 new file mode 100644 index 0000000..a97b145 --- /dev/null +++ b/molecule/default/tests/test_default.py @@ -0,0 +1,26 @@ +"""Role testing files using testinfra.""" + + +def test_lvm_package_shall_be_installed(host): + assert host.package("lvm2").is_installed + + +def test_non_persistent_volume_group_is_created(host): + command = """sudo vgdisplay | grep -c 'my_vg'""" + cmd = host.run(command) + assert '1' in cmd.stdout + + +def test_mylv_logical_volume_is_created(host): + command = """sudo lvs -o lv_name my_vg --separator='|' --noheadings \ + | grep -c 'my_lv'""" + cmd = host.run(command) + assert int(cmd.stdout.rstrip()) >= 1 + + +def test_volume_is_mounted(host): + host.file("/var/lib/mountpoint").mode == 0o731 + + +def test_volume2_is_mounted(host): + host.file("/var/lib/mountpoint2").mode == 0o731 diff --git a/tasks/centos.yml b/tasks/centos.yml index 66cab6b..0d897f3 100644 --- a/tasks/centos.yml +++ b/tasks/centos.yml @@ -1,18 +1,38 @@ --- - name: centos | installing lvm2 - yum: + package: name: "lvm2" state: "present" become: true - name: centos | installing sg3_utils - yum: + package: name: "sg3_utils" state: "present" become: true +- name: centos | install xfs tools + package: + name: "xfsprogs" + state: "present" + become: yes + loop: "{{ lvm_groups|subelements('lvnames') }}" + when: > + ( + (item.1 is defined and item.1 != 'None') and + ( + item.1.filesystem is defined and + item.1.filesystem == "xfs" + ) + and + ( + item.1.create is defined and + item.1.create + ) + ) + - name: centos | checking for scsi devices - shell: "sg_scan" + command: "sg_scan" become: true register: "scsi_devices" changed_when: False diff --git a/tasks/create_fs.yml b/tasks/create_fs.yml new file mode 100644 index 0000000..dbfea2d --- /dev/null +++ b/tasks/create_fs.yml @@ -0,0 +1,110 @@ +--- +- name: manage_lvm | unmounting filesystem(s) + mount: + path: "{{ lv.mntp }}" + src: "/dev/{{ vg.vgname }}/{{ lv.lvname }}" + fstype: "{{ lv.filesystem | default(omit) }}" + state: "absent" + become: true + loop: "{{ vg.lvnames }}" + loop_control: + loop_var: lv + when: > + (lv is defined and + lv != 'None') and + (lv.create is defined and + not lv.create and + lv.filesystem != "swap") + +- name: manage_lvm | creating new filesystem on new LVM logical volume(s) + filesystem: + fstype: "{{ lv.filesystem }}" + dev: "/dev/{{ vg.vgname }}/{{ lv.lvname }}" + resizefs: yes + loop: "{{ vg.lvnames }}" + loop_control: + loop_var: lv + become: true + when: > + ( + (vg.create is defined and + vg.create) and + (lv is defined and + lv != 'None') and + (lv.create is defined and + lv.create) and + ( + lv.filesystem is defined and + lv.filesystem != 'None' and + lv.filesystem != 'xfs' + ) + ) + # unable to resize xfs: looks like we've to reference the mountpoint instead of the device + +- name: lvm | check already converted + # at least xfs is executed twice if the partition has changed in the meantime + # then it tries to recreate the fs on the mounted fs which indeed fails... + shell: "xfs_info /dev/{{ vg.vgname }}/{{ lv.lvname }} | grep -c 'ftype=1'" + become: yes + loop: "{{ vg.lvnames }}" + loop_control: + loop_var: lv + register: mountedxfs + ignore_errors: True + changed_when: no + when: > + ( + (lv is defined and lv != 'None') and + ( + lv.filesystem is defined and + lv.filesystem == "xfs" + ) + and + ( + lv.create is defined and + lv.create + ) + ) + +- name: manage_lvm | creating new xfs filesystem on new LVM logical volume(s) + filesystem: + fstype: "{{ lv.filesystem }}" + dev: "/dev/{{ vg.vgname }}/{{ lv.lvname }}" + loop: "{{ vg.lvnames }}" + loop_control: + loop_var: lv + become: true + when: > + ( + mountedxfs is failed and + (vg.create is defined and + vg.create) and + (lv is defined and + lv != 'None') and + (lv.create is defined and + lv.create) and + ( + lv.filesystem is defined and + lv.filesystem == 'xfs' + ) + ) + +- name: manage_lvm | mounting new filesystem(s) + mount: + path: "{{ lv.mntp }}" + src: "/dev/{{ vg.vgname }}/{{ lv.lvname }}" + fstype: "{{ lv.filesystem }}" + state: "mounted" + opts: "{{ lv.mopts | default('defaults') }}" + become: true + loop: "{{ vg.lvnames }}" + loop_control: + loop_var: lv + when: > + ((vg.create is defined and + vg.create) and + lv != 'None' and + (lv.create is defined and + lv.create) and + (lv.mount is defined and + lv.mount)) diff --git a/tasks/create_lv.yml b/tasks/create_lv.yml new file mode 100644 index 0000000..983e420 --- /dev/null +++ b/tasks/create_lv.yml @@ -0,0 +1,30 @@ +--- +- debug: var=vg + +- name: "debug lvm" + loop: "{{ vg.lvnames }}" + debug: var=lv + loop_control: + loop_var: lv + +- name: manage_lvm | creating new LVM logical volume(s) + lvol: + vg: "{{ vg.vgname }}" + lv: "{{ lv.lvname }}" + size: "{{ lv.size }}" + shrink: no + opts: "{{ lv.opts | default('') }}" + state: "present" + loop: "{{ vg.lvnames }}" + loop_control: + loop_var: lv + become: true + when: > + ( + (vg.create is defined + and vg.create) and + (lv is defined and + lv != 'None') and + (lv.create is defined and + lv.create) + ) diff --git a/tasks/create_vg.yml b/tasks/create_vg.yml new file mode 100644 index 0000000..d79f362 --- /dev/null +++ b/tasks/create_vg.yml @@ -0,0 +1,12 @@ +--- + +- name: manage_lvm | creating new LVM volume group(s) + lvg: + vg: "{{ item.vgname }}" + pvs: "{{ item.disks | join(',') }}" + state: "present" + become: true + loop: "{{ lvm_groups }}" + when: > + item.create is defined and + item.create diff --git a/tasks/debian.yml b/tasks/debian.yml index 3b38eaf..cc489f2 100644 --- a/tasks/debian.yml +++ b/tasks/debian.yml @@ -1,22 +1,40 @@ --- - name: debian | installing pre-reqs - apt: + package: name: - lvm2 - scsitools - - xfsprogs state: "present" become: true +- name: debian | install xfs tools + package: + name: "xfsprogs" + state: "present" + become: yes + loop: "{{ lvm_groups|subelements('lvnames') }}" + when: > + ( + (item.1 is defined and item.1 != 'None') and + ( + item.1.filesystem is defined and + item.1.filesystem == "xfs" + ) + and + ( + item.1.create is defined and + item.1.create + ) + ) - name: debian | checking for scsi devices - shell: "sg_scan" + command: "sg_scan" become: true register: "scsi_devices" - changed_when: False + changed_when: false - name: debian | rescanning for new disks added command: "/sbin/rescan-scsi-bus" become: true - changed_when: False - when: scsi_devices['stdout'] != "" + changed_when: false + when: scsi_devices['stdout'] | length diff --git a/tasks/main.yml b/tasks/main.yml index 96ebddf..34c5d10 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -1,12 +1,12 @@ --- # tasks file for ansible-manage-lvm -- include: debian.yml +- include_tasks: debian.yml when: ansible_os_family == "Debian" -- include: centos.yml +- include_tasks: centos.yml when: ansible_os_family == "RedHat" -- include: manage_lvm.yml +- include_tasks: manage_lvm.yml when: > - manage_lvm and - lvm_groups is defined + manage_lvm and + lvm_groups is defined diff --git a/tasks/manage_lvm.yml b/tasks/manage_lvm.yml index 872977b..e224bff 100644 --- a/tasks/manage_lvm.yml +++ b/tasks/manage_lvm.yml @@ -1,164 +1,40 @@ --- -- name: manage_lvm | creating new LVM volume group(s) - lvg: - vg: "{{ item['vgname'] }}" - pvs: "{{ item['disks']|join(',') }}" - state: "present" - become: true - with_items: "{{ lvm_groups }}" - when: > - (item['create'] is defined and - item['create']) +- name: manage_lvm | manage physical volume group creation + include_tasks: create_vg.yml -- name: manage_lvm | creating new LVM logical volume(s) - lvol: - vg: "{{ item[0]['vgname'] }}" - lv: "{{ item[1]['lvname'] }}" - size: "{{ item[1]['size'] }}" - shrink: no - opts: "{{ item[1]['opts'] | default('') }}" - state: "present" - become: true - register: lvm - with_subelements: - - "{{ lvm_groups }}" - - lvnames - when: > - ((item[0]['create'] is defined - and item[0]['create']) and - (item[1] is defined and - item[1] != 'None') and - (item[1]['create'] is defined and - item[1]['create'])) +- name: manage_lvm | loop over logical volume group(s) to create logical volumes + include_tasks: create_lv.yml + loop: "{{ lvm_groups }}" + loop_control: + loop_var: vg -- name: manage_lvm | creating new filesystem on new LVM logical volume(s) - filesystem: - fstype: "{{ item[1]['filesystem'] }}" - dev: "/dev/{{ item[0]['vgname'] }}/{{ item[1]['lvname'] }}" - # resizefs: yes #coming in 2.0 which will replace the resizing filesystem task below - become: true - with_subelements: - - "{{ lvm_groups }}" - - lvnames - when: > - ((item[0]['create'] is defined and - item[0]['create']) and - (item[1] is defined and - item[1] != 'None') and - (item[1]['create'] is defined and - item[1]['create']) and - (item[1]['filesystem'] is defined and - item[1]['filesystem'] != 'None') and - item[1]['filesystem'] != "swap") - -- name: manage_lvm | mounting new filesystem(s) - mount: - name: "{{ item[1]['mntp'] }}" - src: "/dev/{{ item[0]['vgname'] }}/{{ item[1]['lvname'] }}" - fstype: "{{ item[1]['filesystem'] }}" - state: "mounted" - opts: "{{ item[1]['mopts'] | default('defaults') }}" - become: true - with_subelements: - - "{{ lvm_groups }}" - - lvnames - when: > - ((item[0]['create'] is defined and - item[0]['create']) and - (item[1] is defined and - item[1] != 'None') and - (item[1]['create'] is defined and - item[1]['create']) and - (item[1]['mount'] is defined and - item[1]['mount'])) - -- name: manage_lvm | resizing filesystem - command: resize2fs /dev/{{ item[0]['vgname'] }}/{{ item[1]['lvname'] }} - become: true - with_subelements: - - "{{ lvm_groups }}" - - lvnames - when: > - lvm['changed'] and - item[1]['filesystem'] is defined and - item[1]['filesystem'] != "None" and - item[1]['filesystem'] != "swap" and - item[1]['filesystem'] != "xfs" and - item[1]['filesystem'] != "btrfs" - -- name: manage_lvm | resizing xfs - command: xfs_growfs -d {{ item[1]['mntp'] }} - become: true - with_subelements: - - "{{ lvm_groups }}" - - lvnames - when: > - lvm['changed'] and - item[1]['filesystem'] is defined and - item[1]['filesystem'] == "xfs" - -- name: manage_lvm | resizing swap - shell: "swapoff -a && mkswap /dev/{{ item[0]['vgname'] }}/{{ item[1]['lvname'] }} && swapon -va" - become: true - with_subelements: - - "{{ lvm_groups }}" - - lvnames - when: > - lvm['changed'] and - item[1]['filesystem'] is defined and - item[1]['filesystem'] == "swap" - -- name: manage_lvm | resizing btrfs - shell: "btrfs filesystem resize max {{ item[1]['mntp'] }}" - become: true - with_subelements: - - "{{ lvm_groups }}" - - lvnames - when: > - lvm['changed'] and - item[1]['filesystem'] is defined and - item[1]['filesystem'] == "btrfs" - -- name: manage_lvm | unmounting filesystem(s) - mount: - name: "{{ item[1]['mntp'] }}" - src: "/dev/{{ item[0]['vgname'] }}/{{ item[1]['lvname'] }}" - fstype: "{{ item[1]['filesystem'] | default(omit) }}" - state: "absent" - become: true - with_subelements: - - "{{ lvm_groups }}" - - lvnames - when: > - (item[1] is defined and - item[1] != 'None') and - (item[1]['create'] is defined and - not item[1]['create'] and - item[1]['filesystem'] != "swap") +- name: manage_lvm | loop over logical volume group(s) to create filesystems + include_tasks: create_fs.yml + loop: "{{ lvm_groups }}" + loop_control: + loop_var: vg - name: manage_lvm | Removing LVM logical volume(s) lvol: - vg: "{{ item[0]['vgname'] }}" - lv: "{{ item[1]['lvname'] }}" + vg: "{{ item.0.vgname }}" + lv: "{{ item.1.lvname }}" state: "absent" force: yes become: true - with_subelements: - - "{{ lvm_groups }}" - - lvnames + loop: "{{ lvm_groups|subelements('lvnames') }}" when: > - (item[1] is defined and - item[1] != 'None') and - (item[1]['create'] is defined and - not item[1]['create']) + (item.1 is defined and + item.1 != 'None') and + (item.1.create is defined and + not item.1.create) - name: manage_lvm | Removing LVM volume group(s) lvg: - vg: "{{ item['vgname'] }}" - pvs: "{{ item['disks']|join(',') }}" + vg: "{{ item.vgname }}" + pvs: "{{ item.disks | join(',') }}" state: "absent" become: true - with_items: "{{ lvm_groups }}" + loop: "{{ lvm_groups }}" when: > - item['create'] is defined and - not item['create'] + item.create is defined and + not item.create diff --git a/tests/Dockerfile.debian-jessie b/tests/Dockerfile.debian-jessie deleted file mode 100644 index 2bb5bc2..0000000 --- a/tests/Dockerfile.debian-jessie +++ /dev/null @@ -1,14 +0,0 @@ -FROM debian:jessie -ENV container=docker - -RUN apt-get update && \ - apt-get install -y --no-install-recommends build-essential libffi-dev \ - libssl-dev python-dev python-minimal python-pip python-setuptools \ - python-virtualenv && \ - rm -rf /var/lib/apt/lists/* - -RUN pip install --upgrade pip setuptools && \ - pip install enum34 ipaddress wheel && \ - pip install ansible ansible-lint - -COPY .ansible-lint / diff --git a/tests/Dockerfile.fedora-24 b/tests/Dockerfile.fedora-24 deleted file mode 100644 index b2a83cc..0000000 --- a/tests/Dockerfile.fedora-24 +++ /dev/null @@ -1,26 +0,0 @@ -FROM fedora:24 -ENV container=docker - -RUN dnf -y install gmp-devel libffi-devel openssl-devel python-crypto \ - python-devel python-dnf python-pip python-setuptools python-virtualenv \ - redhat-rpm-config systemd && \ - dnf -y group install "C Development Tools and Libraries" - -# Install systemd -- See https://hub.docker.com/_/centos/ -RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == systemd-tmpfiles-setup.service ] || rm -f $i; done); \ - rm -f /lib/systemd/system/multi-user.target.wants/*;\ - rm -f /etc/systemd/system/*.wants/*;\ - rm -f /lib/systemd/system/local-fs.target.wants/*; \ - rm -f /lib/systemd/system/sockets.target.wants/*udev*; \ - rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \ - rm -f /lib/systemd/system/basic.target.wants/*;\ - rm -f /lib/systemd/system/anaconda.target.wants/*; - -RUN pip install enum34 ipaddress wheel && \ - pip install ansible ansible-lint - -COPY .ansible-lint / - -VOLUME ["/sys/fs/cgroup"] - -CMD ["/usr/sbin/init"] diff --git a/tests/Dockerfile.ubuntu-trusty b/tests/Dockerfile.ubuntu-trusty deleted file mode 100644 index b1645da..0000000 --- a/tests/Dockerfile.ubuntu-trusty +++ /dev/null @@ -1,14 +0,0 @@ -FROM ubuntu:trusty -ENV container=docker - -RUN apt-get update && \ - apt-get install -y --no-install-recommends build-essential libffi-dev \ - libssl-dev python-dev python-minimal python-pip python-setuptools \ - python-virtualenv && \ - rm -rf /var/lib/apt/lists/* - -RUN pip install --upgrade pip setuptools && \ - pip install enum34 ipaddress wheel && \ - pip install ansible ansible-lint - -COPY .ansible-lint /