diff --git a/.github/workflows/molecule.yml b/.github/workflows/molecule.yml new file mode 100644 index 0000000..4ac0ec3 --- /dev/null +++ b/.github/workflows/molecule.yml @@ -0,0 +1,112 @@ +--- + +# 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: + # This workflow contains a single job called "build" + 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 + sudo pip3 install wheel + sudo pip3 install docker molecule testinfra yamllint ansible-lint flake8 + + - name: molecule lint + run: | + molecule lint + + requirements: + # 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 prereq + run: | + ansible-galaxy collection install -r requirements.yml + ansible-galaxy role install -r requirements.yml + + 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/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..73f69e0 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/ansible-manage-lvm.iml b/.idea/ansible-manage-lvm.iml new file mode 100644 index 0000000..d0876a7 --- /dev/null +++ b/.idea/ansible-manage-lvm.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..8656114 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..900cbad --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/handlers/main.yml b/handlers/main.yml index 2027eb2..db4600d 100644 --- a/handlers/main.yml +++ b/handlers/main.yml @@ -1,2 +1,44 @@ --- # handlers file for ansible-manage-lvm +- 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: > + item[1]['filesystem'] is defined and + item[1]['filesystem'] == "swap" + +- name: manage_lvm | resizing btrfs + command: "btrfs filesystem resize max {{ item[1]['mntp'] }}" + become: true + with_subelements: + - "{{ lvm_groups }}" + - lvnames + when: > + item[1]['filesystem'] is defined 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: > + item[1]['filesystem'] is defined and + item[1]['filesystem'] == "xfs" + +- name: manage_lvm | resizing filesystem + command: resize2fs /dev/{{ item[0]['vgname'] }}/{{ item[1]['lvname'] }} + become: true + with_subelements: + - "{{ lvm_groups }}" + - lvnames + when: > + 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" diff --git a/molecule/default/converge.yml b/molecule/default/converge.yml new file mode 100644 index 0000000..9848cce --- /dev/null +++ b/molecule/default/converge.yml @@ -0,0 +1,28 @@ +--- +- 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 + mntp: "/var/lib/mountpoint" + - lvname: my_lv2 + size: 10%VG + opts: "--wipesignatures y" + create: true + filesystem: ext4 + 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/__pycache__/conftest.cpython-27-PYTEST.pyc b/molecule/default/tests/__pycache__/conftest.cpython-27-PYTEST.pyc new file mode 100644 index 0000000..4cd4455 Binary files /dev/null and b/molecule/default/tests/__pycache__/conftest.cpython-27-PYTEST.pyc differ diff --git a/molecule/default/tests/__pycache__/test_default.cpython-27-PYTEST.pyc b/molecule/default/tests/__pycache__/test_default.cpython-27-PYTEST.pyc new file mode 100644 index 0000000..cb5ebdb Binary files /dev/null and b/molecule/default/tests/__pycache__/test_default.cpython-27-PYTEST.pyc differ 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..ad9e53a --- /dev/null +++ b/molecule/default/tests/test_default.py @@ -0,0 +1,22 @@ +"""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 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_lv.yml b/tasks/create_lv.yml new file mode 100644 index 0000000..24f303f --- /dev/null +++ b/tasks/create_lv.yml @@ -0,0 +1,86 @@ +--- + +- name: manage_lvm | creating new LVM logical volume(s) + lvol: + vg: "{{ vg.item[0]['vgname'] }}" + lv: "{{ vg.item[1]['lvname'] }}" + size: "{{ vg.item[1]['size'] }}" + shrink: no + opts: "{{ vg.item[1]['opts'] | default('') }}" + state: "present" + become: true + notify: + - manage_lvm | resizing swap + - manage_lvm | resizing btrfs + - manage_lvm | resizing xfs + - manage_lvm | resizing filesystem + when: > + ( + (vg.item[0]['create'] is defined + and vg.item[0]['create']) and + (vg.item[1] is defined and + vg.item[1] != 'None') and + (vg.item[1]['create'] is defined and + vg.item[1]['create']) + ) + +- name: manage_lvm | creating new filesystem on new LVM logical volume(s) + filesystem: + fstype: "{{ vg.item[1]['filesystem'] }}" + dev: "/dev/{{ vg.item[0]['vgname'] }}/{{ vg.item[1]['lvname'] }}" + # resizefs: yes #coming in 2.0 which will replace the resizing filesystem task below + become: true + when: > + ( + (vg.item[0]['create'] is defined and + vg.item[0]['create']) and + (vg.item[1] is defined and + vg.item[1] != 'None') and + (vg.item[1]['create'] is defined and + vg.item[1]['create']) and + ( + vg.item[1]['filesystem'] is defined and + vg.item[1]['filesystem'] != 'None' and + vg.item[1]['filesystem'] != "swap" and + vg.item[1]['filesystem'] != "xfs" + ) + ) + +- name: lvm | check already converted + loop: "{{ lvm_groups|subelements('lvnames') }}" + shell: "xfs_info /dev/{{ vg.item.0.vgname }}/{{ vg.item.1.lvname }} | grep -c 'ftype=1'" + become: yes + register: alreadyformattedresult + ignore_errors: True + changed_when: no + when: > + ( + (vg.item.1 is defined and vg.item.1 != 'None') and + ( + vg.item.1.filesystem2 is defined and + vg.item.1.filesystem2 == "xfs" + ) + and + ( + vg.item.1.create is defined and + vg.item.1.create + ) + ) + +- name: manage_lvm | creating new filesystem on new LVM logical volume(s) + command: mkfs.xfs /dev/{{ vg.item.0.vgname }}/{{ vg.item.1.lvname }} + become: yes + when: > + ( + alreadyformattedresult and + (vg.item[0]['create'] is defined and + vg.item[0]['create']) and + (vg.item[1] is defined and + vg.item[1] != 'None') and + (vg.item[1]['create'] is defined and + vg.item[1]['create']) and + ( + vg.item[1]['filesystem'] is defined and + vg.item[1]['filesystem'] == "xfs" + ) + ) diff --git a/tasks/create_vg.yml b/tasks/create_vg.yml new file mode 100644 index 0000000..ba408ae --- /dev/null +++ b/tasks/create_vg.yml @@ -0,0 +1,22 @@ +--- +- name: manage_lvm | check existing physical volume group(s) + shell: "vgdisplay | grep '{{ item['vgname'] }}'" + become: true + with_items: "{{ lvm_groups }}" + ignore_errors: True + changed_when: no + register: vg_exist + +- debug: var=vg_exist + +- name: manage_lvm | creating new LVM physical volume group(s) + lvg: + vg: "{{ item.item['vgname'] }}" + pvs: "{{ item.item['disks']|join(',') }}" + state: "present" + become: true + with_items: "{{ vg_exist.results }}" + when: > + item.rc != 0 and + item.item['create'] is defined and + item.item['create'] diff --git a/tasks/debian.yml b/tasks/debian.yml index 3b38eaf..0ccccbf 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: 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: 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/manage_lvm.yml b/tasks/manage_lvm.yml index 872977b..c2f9ae1 100644 --- a/tasks/manage_lvm.yml +++ b/tasks/manage_lvm.yml @@ -1,123 +1,26 @@ --- -- 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: 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" +- name: manage_lvm | check existing logical volume group(s) + shell: "lvs -o lv_name {{ item[0]['vgname'] }} --separator='|' --noheadings | grep {{ item[1]['lvname'] }}" become: true - register: lvm + ignore_errors: True + changed_when: no 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'])) + register: lv_exist -- 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") +- debug: var=lv_exist -- 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 +- name: manage_lvm | loop over logical volume(s) + include: create_lv.yml + loop: "{{ lv_exist.results }}" + loop_control: + loop_var: vg 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" + vg.rc != 0 - name: manage_lvm | unmounting filesystem(s) mount: @@ -136,6 +39,29 @@ not item[1]['create'] and item[1]['filesystem'] != "swap") +- meta: flush_handlers + +- 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 | Removing LVM logical volume(s) lvol: vg: "{{ item[0]['vgname'] }}" @@ -152,7 +78,7 @@ (item[1]['create'] is defined and not item[1]['create']) -- name: manage_lvm | Removing LVM volume group(s) +- name: manage_lvm | Removing LVM physical volume group(s) lvg: vg: "{{ item['vgname'] }}" pvs: "{{ item['disks']|join(',') }}"