lvol - extending volumes with '+' only work for percentages (#2267)

* Merged changes from old PR

* Added suppurt for -, other adaptations regarding size.

* Implementing +- support for -l

* Added changelog

* Renamed changelog

* Apply suggestions from code review

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

Co-authored-by: Felix Fontein <felix@fontein.de>
pull/2354/head
zigaSRC 2021-04-26 07:07:14 +02:00 committed by GitHub
parent aea12899cc
commit ffd73296de
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 62 additions and 16 deletions

View File

@ -0,0 +1,5 @@
---
minor_changes:
- lvol - added proper support for ``+-`` options when extending or reducing the logical volume (https://github.com/ansible-collections/community.general/issues/1988).
bugfixes:
- lvol - fixed sizing calculation rounding to match the underlying tools (https://github.com/ansible-collections/community.general/issues/1988).

View File

@ -12,6 +12,8 @@ DOCUMENTATION = '''
author: author:
- Jeroen Hoekx (@jhoekx) - Jeroen Hoekx (@jhoekx)
- Alexander Bulimov (@abulimov) - Alexander Bulimov (@abulimov)
- Raoul Baudach (@unkaputtbar112)
- Ziga Kern (@zigaSRC)
module: lvol module: lvol
short_description: Configure LVM logical volumes short_description: Configure LVM logical volumes
description: description:
@ -33,7 +35,11 @@ options:
default in megabytes or optionally with one of [bBsSkKmMgGtTpPeE] units; or default in megabytes or optionally with one of [bBsSkKmMgGtTpPeE] units; or
according to lvcreate(8) --extents as a percentage of [VG|PVS|FREE]; according to lvcreate(8) --extents as a percentage of [VG|PVS|FREE];
Float values must begin with a digit. Float values must begin with a digit.
Resizing using percentage values was not supported prior to 2.1. - When resizing, apart from specifying an absolute size you may, according to
lvextend(8)|lvreduce(8) C(--size), specify the amount to extend the logical volume with
the prefix C(+) or the amount to reduce the logical volume by with prefix C(-).
- Resizing using C(+) or C(-) was not supported prior to community.general 3.0.0.
- Please note that when using C(+) or C(-), the module is B(not idempotent).
state: state:
type: str type: str
description: description:
@ -136,6 +142,12 @@ EXAMPLES = '''
lv: test lv: test
size: +100%FREE size: +100%FREE
- name: Extend the logical volume by given space
community.general.lvol:
vg: firefly
lv: test
size: +512M
- name: Extend the logical volume to take all remaining space of the PVs and resize the underlying filesystem - name: Extend the logical volume to take all remaining space of the PVs and resize the underlying filesystem
community.general.lvol: community.general.lvol:
vg: firefly vg: firefly
@ -157,6 +169,13 @@ EXAMPLES = '''
size: 512 size: 512
force: yes force: yes
- name: Reduce the logical volume by given space
community.general.lvol:
vg: firefly
lv: test
size: -512M
force: yes
- name: Set the logical volume to 512m and do not try to shrink if size is lower than current one - name: Set the logical volume to 512m and do not try to shrink if size is lower than current one
community.general.lvol: community.general.lvol:
vg: firefly vg: firefly
@ -209,7 +228,6 @@ import re
from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.basic import AnsibleModule
LVOL_ENV_VARS = dict( LVOL_ENV_VARS = dict(
# make sure we use the C locale when running lvol-related commands # make sure we use the C locale when running lvol-related commands
LANG='C', LANG='C',
@ -307,6 +325,7 @@ def main():
thinpool = module.params['thinpool'] thinpool = module.params['thinpool']
size_opt = 'L' size_opt = 'L'
size_unit = 'm' size_unit = 'm'
size_operator = None
snapshot = module.params['snapshot'] snapshot = module.params['snapshot']
pvs = module.params['pvs'] pvs = module.params['pvs']
@ -325,7 +344,16 @@ def main():
test_opt = '' test_opt = ''
if size: if size:
# LVCREATE(8) -l --extents option with percentage # LVEXTEND(8)/LVREDUCE(8) -l, -L options: Check for relative value for resizing
if size.startswith('+'):
size_operator = '+'
size = size[1:]
elif size.startswith('-'):
size_operator = '-'
size = size[1:]
# LVCREATE(8) does not support [+-]
# LVCREATE(8)/LVEXTEND(8)/LVREDUCE(8) -l --extents option with percentage
if '%' in size: if '%' in size:
size_parts = size.split('%', 1) size_parts = size.split('%', 1)
size_percent = int(size_parts[0]) size_percent = int(size_parts[0])
@ -339,10 +367,10 @@ def main():
size_opt = 'l' size_opt = 'l'
size_unit = '' size_unit = ''
# LVCREATE(8)/LVEXTEND(8)/LVREDUCE(8) -L --size option unit
if '%' not in size: if '%' not in size:
# LVCREATE(8) -L --size option unit
if size[-1].lower() in 'bskmgtpe': if size[-1].lower() in 'bskmgtpe':
size_unit = size[-1].lower() size_unit = size[-1]
size = size[0:-1] size = size[0:-1]
try: try:
@ -398,7 +426,6 @@ def main():
else: else:
module.fail_json(msg="Snapshot origin LV %s does not exist in volume group %s." % (lv, vg)) module.fail_json(msg="Snapshot origin LV %s does not exist in volume group %s." % (lv, vg))
check_lv = snapshot check_lv = snapshot
elif thinpool: elif thinpool:
if lv: if lv:
# Check thin volume pre-conditions # Check thin volume pre-conditions
@ -423,6 +450,8 @@ def main():
msg = '' msg = ''
if this_lv is None: if this_lv is None:
if state == 'present': if state == 'present':
if size_operator is not None:
module.fail_json(msg="Bad size specification of '%s%s' for creating LV" % (size_operator, size))
# Require size argument except for snapshot of thin volumes # Require size argument except for snapshot of thin volumes
if (lv or thinpool) and not size: if (lv or thinpool) and not size:
for test_lv in lvs: for test_lv in lvs:
@ -476,13 +505,19 @@ def main():
else: # size_whole == 'FREE': else: # size_whole == 'FREE':
size_requested = size_percent * this_vg['free'] / 100 size_requested = size_percent * this_vg['free'] / 100
# Round down to the next lowest whole physical extent # from LVEXTEND(8) - The resulting value is rounded upward.
size_requested -= (size_requested % this_vg['ext_size']) # from LVREDUCE(8) - The resulting value for the substraction is rounded downward, for the absolute size it is rounded upward.
if size_operator == '+':
if '+' in size:
size_requested += this_lv['size'] size_requested += this_lv['size']
size_requested += this_vg['ext_size'] - (size_requested % this_vg['ext_size'])
elif size_operator == '-':
size_requested = this_lv['size'] - size_requested
size_requested -= (size_requested % this_vg['ext_size'])
else:
size_requested += this_vg['ext_size'] - (size_requested % this_vg['ext_size'])
if this_lv['size'] < size_requested: if this_lv['size'] < size_requested:
if (size_free > 0) and (('+' not in size) or (size_free >= (size_requested - this_lv['size']))): if (size_free > 0) and (size_free >= (size_requested - this_lv['size'])):
tool = module.get_bin_path("lvextend", required=True) tool = module.get_bin_path("lvextend", required=True)
else: else:
module.fail_json( module.fail_json(
@ -490,7 +525,7 @@ def main():
(this_lv['name'], (size_requested - this_lv['size']), unit, size_free, unit) (this_lv['name'], (size_requested - this_lv['size']), unit, size_free, unit)
) )
elif shrink and this_lv['size'] > size_requested + this_vg['ext_size']: # more than an extent too large elif shrink and this_lv['size'] > size_requested + this_vg['ext_size']: # more than an extent too large
if size_requested == 0: if size_requested < 1:
module.fail_json(msg="Sorry, no shrinking of %s to 0 permitted." % (this_lv['name'])) module.fail_json(msg="Sorry, no shrinking of %s to 0 permitted." % (this_lv['name']))
elif not force: elif not force:
module.fail_json(msg="Sorry, no shrinking of %s without force=yes" % (this_lv['name'])) module.fail_json(msg="Sorry, no shrinking of %s without force=yes" % (this_lv['name']))
@ -501,7 +536,10 @@ def main():
if tool: if tool:
if resizefs: if resizefs:
tool = '%s %s' % (tool, '--resizefs') tool = '%s %s' % (tool, '--resizefs')
cmd = "%s %s -%s %s%s %s/%s %s" % (tool, test_opt, size_opt, size, size_unit, vg, this_lv['name'], pvs) if size_operator:
cmd = "%s %s -%s %s%s%s %s/%s %s" % (tool, test_opt, size_opt, size_operator, size, size_unit, vg, this_lv['name'], pvs)
else:
cmd = "%s %s -%s %s%s %s/%s %s" % (tool, test_opt, size_opt, size, size_unit, vg, this_lv['name'], pvs)
rc, out, err = module.run_command(cmd) rc, out, err = module.run_command(cmd)
if "Reached maximum COW size" in out: if "Reached maximum COW size" in out:
module.fail_json(msg="Unable to resize %s to %s%s" % (lv, size, size_unit), rc=rc, err=err, out=out) module.fail_json(msg="Unable to resize %s to %s%s" % (lv, size, size_unit), rc=rc, err=err, out=out)
@ -518,9 +556,9 @@ def main():
else: else:
# resize LV based on absolute values # resize LV based on absolute values
tool = None tool = None
if float(size) > this_lv['size']: if float(size) > this_lv['size'] or size_operator == '+':
tool = module.get_bin_path("lvextend", required=True) tool = module.get_bin_path("lvextend", required=True)
elif shrink and float(size) < this_lv['size']: elif shrink and float(size) < this_lv['size'] or size_operator == '-':
if float(size) == 0: if float(size) == 0:
module.fail_json(msg="Sorry, no shrinking of %s to 0 permitted." % (this_lv['name'])) module.fail_json(msg="Sorry, no shrinking of %s to 0 permitted." % (this_lv['name']))
if not force: if not force:
@ -532,7 +570,10 @@ def main():
if tool: if tool:
if resizefs: if resizefs:
tool = '%s %s' % (tool, '--resizefs') tool = '%s %s' % (tool, '--resizefs')
cmd = "%s %s -%s %s%s %s/%s %s" % (tool, test_opt, size_opt, size, size_unit, vg, this_lv['name'], pvs) if size_operator:
cmd = "%s %s -%s %s%s%s %s/%s %s" % (tool, test_opt, size_opt, size_operator, size, size_unit, vg, this_lv['name'], pvs)
else:
cmd = "%s %s -%s %s%s %s/%s %s" % (tool, test_opt, size_opt, size, size_unit, vg, this_lv['name'], pvs)
rc, out, err = module.run_command(cmd) rc, out, err = module.run_command(cmd)
if "Reached maximum COW size" in out: if "Reached maximum COW size" in out:
module.fail_json(msg="Unable to resize %s to %s%s" % (lv, size, size_unit), rc=rc, err=err, out=out) module.fail_json(msg="Unable to resize %s to %s%s" % (lv, size, size_unit), rc=rc, err=err, out=out)