From 9de5c0c53ce0e98ff82f1334987ba50be56d1c4c Mon Sep 17 00:00:00 2001
From: cassio-santos <33725931+cassio-santos@users.noreply.github.com>
Date: Fri, 29 May 2020 16:16:23 -0300
Subject: [PATCH] LVG: add new parameter pvresize (#422)

* enabling resize in pv.

* change pvresize default behavior to false

* includes changelog on pvresize

* punctuation fix

Co-authored-by: Andrew Klychkov <aaklychkov@mail.ru>

* fixes typo and changes pvresize_cmd location

* Update changelogs/fragments/442-add-new-parameter-pvresize.yaml

Co-authored-by: Andrew Klychkov <aaklychkov@mail.ru>

* Update plugins/modules/system/lvg.py

Co-authored-by: Andrew Klychkov <aaklychkov@mail.ru>

* rebase and add EXAMPLE for pvresize

* fix wrongly submited merge conflict

* Update plugins/modules/system/lvg.py

Co-authored-by: Felix Fontein <felix@fontein.de>

* adding tests

* add test for check_mode

* fix identation

* Update tests/integration/targets/lvg/tasks/test_pvresize.yml

Co-authored-by: Andrew Klychkov <aaklychkov@mail.ru>

* Update tests/integration/targets/lvg/tasks/test_pvresize.yml

Co-authored-by: Andrew Klychkov <aaklychkov@mail.ru>

* fix identation

Co-authored-by: CASSIO ALVES <cassioalves@bocombbm.com.br>
Co-authored-by: Andrew Klychkov <aaklychkov@mail.ru>
Co-authored-by: Felix Fontein <felix@fontein.de>
Co-authored-by: cassio alves <cassio@localhost.localdomain>
---
 .../442-add-new-parameter-pvresize.yaml       |  2 +
 plugins/modules/system/lvg.py                 | 38 ++++++++++
 tests/integration/targets/lvg/tasks/main.yml  |  2 +
 .../targets/lvg/tasks/test_pvresize.yml       | 76 +++++++++++++++++++
 4 files changed, 118 insertions(+)
 create mode 100644 changelogs/fragments/442-add-new-parameter-pvresize.yaml
 create mode 100644 tests/integration/targets/lvg/tasks/test_pvresize.yml

diff --git a/changelogs/fragments/442-add-new-parameter-pvresize.yaml b/changelogs/fragments/442-add-new-parameter-pvresize.yaml
new file mode 100644
index 0000000000..b41ff48c48
--- /dev/null
+++ b/changelogs/fragments/442-add-new-parameter-pvresize.yaml
@@ -0,0 +1,2 @@
+minor_changes:
+    - lvg - add ``pvresize`` new parameter (https://github.com/ansible/ansible/issues/29139).
diff --git a/plugins/modules/system/lvg.py b/plugins/modules/system/lvg.py
index 18924f5678..4000726b03 100644
--- a/plugins/modules/system/lvg.py
+++ b/plugins/modules/system/lvg.py
@@ -40,6 +40,11 @@ options:
     description:
     - Additional options to pass to C(pvcreate) when creating the volume group.
     type: str
+  pvresize:
+    description:
+    - If C(yes), resize the physical volume to the maximum available size.
+    type: bool
+    default: false
   vg_options:
     description:
     - Additional options to pass to C(vgcreate) when creating the volume group.
@@ -89,6 +94,12 @@ EXAMPLES = r'''
   lvg:
     vg: vg.services
     state: absent
+
+- name: Create a volume group on top of /dev/sda3 and resize the volume group /dev/sda3 to the maximum possible
+  lvg:
+    vg: resizableVG
+    pvs: /dev/sda3
+    pvresize: yes
 '''
 
 import itertools
@@ -140,6 +151,7 @@ def main():
             pvs=dict(type='list'),
             pesize=dict(type='str', default='4'),
             pv_options=dict(type='str', default=''),
+            pvresize=dict(type='bool', default=False),
             vg_options=dict(type='str', default=''),
             state=dict(type='str', default='present', choices=['absent', 'present']),
             force=dict(type='bool', default=False),
@@ -150,6 +162,7 @@ def main():
     vg = module.params['vg']
     state = module.params['state']
     force = module.boolean(module.params['force'])
+    pvresize = module.boolean(module.params['pvresize'])
     pesize = module.params['pesize']
     pvoptions = module.params['pv_options'].split()
     vgoptions = module.params['vg_options'].split()
@@ -249,6 +262,31 @@ def main():
         devs_to_remove = list(set(current_devs) - set(dev_list))
         devs_to_add = list(set(dev_list) - set(current_devs))
 
+        if current_devs:
+            if state == 'present' and pvresize:
+                for device in current_devs:
+                    pvresize_cmd = module.get_bin_path('pvresize', True)
+                    pvdisplay_cmd = module.get_bin_path('pvdisplay', True)
+                    pvdisplay_ops = ["--units", "b", "--columns", "--noheadings", "--nosuffix"]
+                    pvdisplay_cmd_device_options = [pvdisplay_cmd, device] + pvdisplay_ops
+                    rc, dev_size, err = module.run_command(pvdisplay_cmd_device_options + ["-o", "dev_size"])
+                    dev_size = int(dev_size.replace(" ", ""))
+                    rc, pv_size, err = module.run_command(pvdisplay_cmd_device_options + ["-o", "pv_size"])
+                    pv_size = int(pv_size.replace(" ", ""))
+                    rc, pe_start, err = module.run_command(pvdisplay_cmd_device_options + ["-o", "pe_start"])
+                    pe_start = int(pe_start.replace(" ", ""))
+                    rc, vg_extent_size, err = module.run_command(pvdisplay_cmd_device_options + ["-o", "vg_extent_size"])
+                    vg_extent_size = int(vg_extent_size.replace(" ", ""))
+                    if (dev_size - (pe_start + pv_size)) > vg_extent_size:
+                        if module.check_mode:
+                            changed = True
+                        else:
+                            rc, _, err = module.run_command([pvresize_cmd, device])
+                            if rc != 0:
+                                module.fail_json(msg="Failed executing pvresize command.", rc=rc, err=err)
+                            else:
+                                changed = True
+
         if devs_to_add or devs_to_remove:
             if module.check_mode:
                 changed = True
diff --git a/tests/integration/targets/lvg/tasks/main.yml b/tests/integration/targets/lvg/tasks/main.yml
index a57f591bf0..f564ef0ed2 100644
--- a/tests/integration/targets/lvg/tasks/main.yml
+++ b/tests/integration/targets/lvg/tasks/main.yml
@@ -11,5 +11,7 @@
     - import_tasks: test_indempotency.yml
 
     - import_tasks: test_grow_reduce.yml
+
+    - import_tasks: test_pvresize.yml
   always:
     - import_tasks: teardown.yml
diff --git a/tests/integration/targets/lvg/tasks/test_pvresize.yml b/tests/integration/targets/lvg/tasks/test_pvresize.yml
new file mode 100644
index 0000000000..9112f8bffa
--- /dev/null
+++ b/tests/integration/targets/lvg/tasks/test_pvresize.yml
@@ -0,0 +1,76 @@
+- name: "Create volume group on first disk"
+  lvg:
+    vg: testvg
+    pvs: "{{ loop_device1.stdout }}"
+
+- name: Gets current vg size
+  shell: vgs -v testvg -o pv_size --noheading --units b | xargs
+  register: cmd_result
+
+- name: Assert the testvg size is 8388608B
+  assert:
+   that:
+    - "'8388608B' == cmd_result.stdout"
+
+- name: Increases size in file
+  command: "dd if=/dev/zero bs=8MiB count=1 of={{ remote_tmp_dir }}/img1 conv=notrunc oflag=append"
+
+- name: "Reread size of file associated with loop_device1"
+  command: "losetup -c {{ loop_device1.stdout }}"
+
+- name: "Reruns lvg with pvresize:no"
+  lvg:
+   vg: testvg
+   pvs: "{{ loop_device1.stdout }}"
+   pvresize: no
+  register: cmd_result
+ 
+- assert:
+    that:
+    - cmd_result is not changed
+
+- name: Gets current vg size
+  shell: vgs -v testvg -o pv_size --noheading --units b | xargs
+  register: cmd_result
+
+- name: Assert the testvg size is still 8388608B
+  assert:
+   that:
+    - "'8388608B' == cmd_result.stdout"
+
+- name: "Reruns lvg with pvresize:yes and check_mode:yes"
+  lvg:
+   vg: testvg
+   pvs: "{{ loop_device1.stdout }}"
+   pvresize: yes
+  check_mode: yes
+  register: cmd_result
+  
+- name: Assert that the module returned the state was changed
+  assert:
+    that:
+    - cmd_result is changed
+
+- name: Gets current vg size
+  shell: vgs -v testvg -o pv_size --noheading --units b | xargs
+  register: cmd_result
+ 
+- name: Assert the testvg size is still 8388608B
+  assert:
+   that:
+    - "'8388608B' == cmd_result.stdout"
+
+- name: "Reruns lvg with pvresize:yes"
+  lvg:
+   vg: testvg
+   pvs: "{{ loop_device1.stdout }}"
+   pvresize: yes
+
+- name: Gets current vg size
+  shell: vgs -v testvg -o pv_size --noheading --units b | xargs
+  register: cmd_result
+
+- name: Assert the testvg size is now 16777216B
+  assert:
+   that:
+    - "'16777216B' == cmd_result.stdout"