Add thin pool / volume managment to lvol (#19312)

* add functionality to create thin pool / volume on Linux LVM to lvol module

add `thinpool' parameter.
change `lv' parameter to not required.

To create thin poll, specify `thinpool'(, `vg' and `size') parameter and omit `lv' parameter.
It will create thin pool, nameed by `thinpool' parameter.

To create thin volume, specify both `thinpool' and `lv' parameter (also `vg' and `size' paramter is need).
It will create thin volume on `thinpool' pool, named by `lv' parameter.

Thin volume and pool can delete whith 'state=absent' parameter.
Thin volume is resizable like normal volume.
Thin pool can extend, but not reduce. This limitation is in Linux's LVM.

* Add thin volume support

- Based on f816618

- Indicate that either lv or thinpool are required parameters using
AnsibleModule's required_one_of.

- Resolve conflict with snapshot functionality

* Fix typo in documentation

* Fix and simplify logical volume check

* Rebase fixes

* Convert examples to native YAML syntax

* Fix failure with snapshot creation

* Properly fail when trying to snapshot a thinpool volume

* Don't fail when no size given for thin volume snapshot

Fixes ansible/ansible-modules-extras#2478

* Convert old style required property sneaked in through rebase

* Fix 'too many leading #' syntax check
pull/35384/head
Reto Gantenbein 7 years ago committed by John R Barker
parent e2af5dfae0
commit 466e1b289b

@ -25,11 +25,9 @@ options:
vg: vg:
description: description:
- The volume group this logical volume is part of. - The volume group this logical volume is part of.
required: true
lv: lv:
description: description:
- The name of the logical volume. - The name of the logical volume.
required: true
size: size:
description: description:
- The size of the logical volume, according to lvcreate(8) --size, by - The size of the logical volume, according to lvcreate(8) --size, by
@ -68,6 +66,10 @@ options:
description: description:
- Comma separated list of physical volumes (e.g. /dev/sda,/dev/sdb). - Comma separated list of physical volumes (e.g. /dev/sda,/dev/sdb).
version_added: "2.2" version_added: "2.2"
thinpool:
description:
- The thin pool volume name. When you want to create a thin provisioned volume, specify a thin pool volume name.
version_added: "2.5"
shrink: shrink:
description: description:
- Shrink if current size is higher than size requested. - Shrink if current size is higher than size requested.
@ -80,6 +82,8 @@ options:
type: bool type: bool
default: 'yes' default: 'yes'
version_added: "2.5" version_added: "2.5"
notes:
- You must specify lv (when managing the state of logical volumes) or thinpool (when managing a thin provisioned volume).
''' '''
EXAMPLES = ''' EXAMPLES = '''
@ -188,6 +192,19 @@ EXAMPLES = '''
lv: test lv: test
size: 512g size: 512g
active: false active: false
# Create a thin pool of 512g.
- lvol:
vg: firefly
thinpool: testpool
size: 512g
# Create a thin volume of 128g.
- lvol:
vg: firefly
lv: test
thinpool: testpool
size: 128g
''' '''
import re import re
@ -208,7 +225,9 @@ def parse_lvs(data):
lvs.append({ lvs.append({
'name': parts[0].replace('[', '').replace(']', ''), 'name': parts[0].replace('[', '').replace(']', ''),
'size': int(decimal_point.match(parts[1]).group(1)), 'size': int(decimal_point.match(parts[1]).group(1)),
'active': (parts[2][4] == 'a') 'active': (parts[2][4] == 'a'),
'thinpool': (parts[2][0] == 't'),
'thinvol': (parts[2][0] == 'V'),
}) })
return lvs return lvs
@ -241,7 +260,7 @@ def main():
module = AnsibleModule( module = AnsibleModule(
argument_spec=dict( argument_spec=dict(
vg=dict(type='str', required=True), vg=dict(type='str', required=True),
lv=dict(type='str', required=True), lv=dict(type='str'),
size=dict(type='str'), size=dict(type='str'),
opts=dict(type='str'), opts=dict(type='str'),
state=dict(type='str', default='present', choices=['absent', 'present']), state=dict(type='str', default='present', choices=['absent', 'present']),
@ -251,8 +270,12 @@ def main():
snapshot=dict(type='str'), snapshot=dict(type='str'),
pvs=dict(type='str'), pvs=dict(type='str'),
resizefs=dict(type='bool', default=False), resizefs=dict(type='bool', default=False),
thinpool=dict(type='str'),
), ),
supports_check_mode=True, supports_check_mode=True,
required_one_of=(
['lv', 'thinpool'],
),
) )
# Determine if the "--yes" option should be used # Determine if the "--yes" option should be used
@ -274,6 +297,7 @@ def main():
shrink = module.boolean(module.params['shrink']) shrink = module.boolean(module.params['shrink'])
active = module.boolean(module.params['active']) active = module.boolean(module.params['active'])
resizefs = module.boolean(module.params['resizefs']) resizefs = module.boolean(module.params['resizefs'])
thinpool = module.params['thinpool']
size_opt = 'L' size_opt = 'L'
size_unit = 'm' size_unit = 'm'
snapshot = module.params['snapshot'] snapshot = module.params['snapshot']
@ -356,10 +380,32 @@ def main():
lvs = parse_lvs(current_lvs) lvs = parse_lvs(current_lvs)
if snapshot is None: if snapshot:
check_lv = lv # Check snapshot pre-conditions
else: for test_lv in lvs:
if test_lv['name'] == lv or test_lv['name'] == thinpool:
if not test_lv['thinpool'] and not thinpool:
break
else:
module.fail_json(msg="Snapshots of thin pool LVs are not supported.")
else:
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:
if lv:
# Check thin volume pre-conditions
for test_lv in lvs:
if test_lv['name'] == thinpool:
break
else:
module.fail_json(msg="Thin pool LV %s does not exist in volume group %s." % (thinpool, vg))
check_lv = lv
else:
check_lv = thinpool
else:
check_lv = lv
for test_lv in lvs: for test_lv in lvs:
if test_lv['name'] in (check_lv, check_lv.rsplit('/', 1)[-1]): if test_lv['name'] in (check_lv, check_lv.rsplit('/', 1)[-1]):
this_lv = test_lv this_lv = test_lv
@ -367,17 +413,31 @@ def main():
else: else:
this_lv = None this_lv = None
if state == 'present' and not size:
if this_lv is None:
module.fail_json(msg="No size given.")
msg = '' msg = ''
if this_lv is None: if this_lv is None:
if state == 'present': if state == 'present':
# Require size argument except for snapshot of thin volumes
if (lv or thinpool) and not size:
for test_lv in lvs:
if test_lv['name'] == lv and test_lv['thinvol'] and snapshot:
break
else:
module.fail_json(msg="No size given.")
# create LV # create LV
lvcreate_cmd = module.get_bin_path("lvcreate", required=True) lvcreate_cmd = module.get_bin_path("lvcreate", required=True)
if snapshot is not None: if snapshot is not None:
cmd = "%s %s %s -%s %s%s -s -n %s %s %s/%s" % (lvcreate_cmd, test_opt, yesopt, size_opt, size, size_unit, snapshot, opts, vg, lv) if size:
cmd = "%s %s %s -%s %s%s -s -n %s %s %s/%s" % (lvcreate_cmd, test_opt, yesopt, size_opt, size, size_unit, snapshot, opts, vg, lv)
else:
cmd = "%s %s %s -s -n %s %s %s/%s" % (lvcreate_cmd, test_opt, yesopt, snapshot, opts, vg, lv)
elif thinpool and lv:
if size_opt == 'l':
module.fail_json(changed=False, msg="Thin volume sizing with percentage not supported.")
size_opt = 'V'
cmd = "%s %s -n %s -%s %s%s %s -T %s/%s" % (lvcreate_cmd, yesopt, lv, size_opt, size, size_unit, opts, vg, thinpool)
elif thinpool and not lv:
cmd = "%s %s -%s %s%s %s -T %s/%s" % (lvcreate_cmd, yesopt, size_opt, size, size_unit, opts, vg, thinpool)
else: else:
cmd = "%s %s %s -n %s -%s %s%s %s %s %s" % (lvcreate_cmd, test_opt, yesopt, lv, size_opt, size, size_unit, opts, vg, pvs) cmd = "%s %s %s -n %s -%s %s%s %s %s %s" % (lvcreate_cmd, test_opt, yesopt, lv, size_opt, size, size_unit, opts, vg, pvs)
rc, _, err = module.run_command(cmd) rc, _, err = module.run_command(cmd)

Loading…
Cancel
Save