Commit c8c0fe94 by Alexander Bulimov

various fixes in lvg module, added ability to reduce and extend VG, added…

various fixes in lvg module, added ability to reduce and extend VG, added Physical Extent parameter, added explicit creation of physical volumes
parent 259d9942
...@@ -25,7 +25,7 @@ author: Alexander Bulimov ...@@ -25,7 +25,7 @@ author: Alexander Bulimov
module: lvg module: lvg
short_description: Configure LVM volume groups short_description: Configure LVM volume groups
description: description:
- This module creates or removes volume groups. - This module creates, removes or resizes volume groups.
version_added: "1.1" version_added: "1.1"
options: options:
vg: vg:
...@@ -36,6 +36,11 @@ options: ...@@ -36,6 +36,11 @@ options:
description: description:
- List of comma-separated devices to use in this volume group. - List of comma-separated devices to use in this volume group.
required: true required: true
pesize:
description:
- The size of the physical extent in megabytes.
default: 4
required: false
state: state:
choices: [ "present", "absent" ] choices: [ "present", "absent" ]
default: present default: present
...@@ -44,19 +49,19 @@ options: ...@@ -44,19 +49,19 @@ options:
required: false required: false
force: force:
choices: [ "yes", "no" ] choices: [ "yes", "no" ]
default: no default: "no"
description: description:
- If yes, allows to remove volume group with logical volumes. - If yes, allows to remove volume group with logical volumes.
required: false required: false
examples: examples:
- description: Create a volume group on top of /dev/sda1. - description: Create a volume group on top of /dev/sda1 with physical extent size = 32MB.
code: lvg vg=vg.services dev=/dev/sda1 code: lvg vg=vg.services dev=/dev/sda1 pesize=32
- description: Create a volume group on top of /dev/sdb1 and /dev/sdc5. - description: Create a volume group on top of /dev/sdb1 and /dev/sdc5.
code: lvg vg=vg.services dev=/dev/sdb1,/dev/sdc5 code: lvg vg=vg.services dev=/dev/sdb1,/dev/sdc5
- description: Remove a volume group with name vg.services. - description: Remove a volume group with name vg.services.
code: lvg vg=vg.services state=absent code: lvg vg=vg.services state=absent
notes: notes:
- module does not check device list for already present volume group - module does not modify PE size for already present volume group
''' '''
def parse_vgs(data): def parse_vgs(data):
...@@ -70,36 +75,63 @@ def parse_vgs(data): ...@@ -70,36 +75,63 @@ def parse_vgs(data):
}) })
return vgs return vgs
def parse_pvs(data):
pvs = []
for line in data.splitlines():
parts = line.strip().split(';')
pvs.append({
'name': parts[0],
'vg_name': parts[1],
})
return pvs
def main(): def main():
module = AnsibleModule( module = AnsibleModule(
argument_spec = dict( argument_spec = dict(
vg=dict(required=True), vg=dict(required=True),
dev=dict(), dev=dict(),
pesize=dict(),
state=dict(choices=["absent", "present"], default='present'), state=dict(choices=["absent", "present"], default='present'),
force=dict(choices=["yes", "no"], default='no'), force=dict(type='bool', default='no'),
), ),
supports_check_mode=True, supports_check_mode=True,
) )
vg = module.params['vg'] vg = module.params['vg']
state = module.params['state']
force = module.boolean(module.params['force'])
if module.params['pesize']:
pesize = int(module.params['pesize'])
else:
pesize = 4
if module.params['dev']: if module.params['dev']:
dev = module.params['dev'].replace(',',' ') dev = module.params['dev'].replace(',',' ')
dev_list = module.params['dev'].split(',') dev_list = module.params['dev'].split(',')
state = module.params['state'] elif state == 'present':
force = module.params['force']
if state=='present' and not dev:
module.fail_json(msg="No dev given.") module.fail_json(msg="No dev given.")
if state=='present': if state=='present':
### check given devices
for test_dev in dev_list: for test_dev in dev_list:
if not os.path.exists(test_dev): if not os.path.exists(test_dev):
module.fail_json(msg="No dev %s found."%test_dev) module.fail_json(msg="No dev %s found."%test_dev)
### get pv list
rc,current_pvs,err = module.run_command("pvs --noheadings -o pv_name,vg_name --separator ';'")
if rc != 0:
module.fail_json(msg="Failed executing pvs command.",rc=rc, err=err)
### check pv for devices
pvs = parse_pvs(current_pvs)
used_pvs = filter(lambda pv: pv['name'] in dev_list and pv['vg_name'] and pv['vg_name'] != vg, pvs)
if used_pvs:
module.fail_json(msg="dev %s is already in %s volume group."%(used_pvs[0]['name'],used_pvs[0]['vg_name']))
rc,current_vgs,err = module.run_command("vgs --noheadings -o vg_name,pv_count,lv_count --separator ';'") rc,current_vgs,err = module.run_command("vgs --noheadings -o vg_name,pv_count,lv_count --separator ';'")
if rc != 0: if rc != 0:
module.fail_json(msg="Failed creating volume group %s."%vg, rc=rc, err=err) module.fail_json(msg="Failed executing vgs command.",rc=rc, err=err)
changed = False changed = False
...@@ -118,17 +150,24 @@ def main(): ...@@ -118,17 +150,24 @@ def main():
if module.check_mode: if module.check_mode:
changed = True changed = True
else: else:
rc,_,err = module.run_command("vgcreate %s %s"%(vg, dev)) ### create PV
for current_dev in dev_list:
rc,_,err = module.run_command("pvcreate %s"%current_dev)
if rc == 0:
changed = True
else:
module.fail_json(msg="Creating physical volume '%s' failed"%current_dev, rc=rc, err=err)
rc,_,err = module.run_command("vgcreate -s %s %s %s"%(pesize, vg, dev))
if rc == 0: if rc == 0:
changed = True changed = True
else: else:
module.fail_json(msg="Creating volume group '%s' failed"%(vg), rc=rc, err=err) module.fail_json(msg="Creating volume group '%s' failed"%vg, rc=rc, err=err)
else: else:
if state == 'absent': if state == 'absent':
if module.check_mode: if module.check_mode:
module.exit_json(changed=True) module.exit_json(changed=True)
else: else:
if this_vg['lv_count'] == 0 or force == "yes": if this_vg['lv_count'] == 0 or force:
### remove VG ### remove VG
rc,_,err = module.run_command("vgremove --force %s"%(vg)) rc,_,err = module.run_command("vgremove --force %s"%(vg))
if rc == 0: if rc == 0:
...@@ -138,6 +177,53 @@ def main(): ...@@ -138,6 +177,53 @@ def main():
else: else:
module.fail_json(msg="Refuse to remove non-empty volume group %s without force=yes"%(vg)) module.fail_json(msg="Refuse to remove non-empty volume group %s without force=yes"%(vg))
### resize VG
action = None
current_devs = map(lambda x: x['name'], filter(lambda pv: pv['vg_name'] == vg, pvs))
devs_to_remove = list(set(current_devs) - set(dev_list))
devs_to_add = list(set(dev_list) - set(current_devs))
if devs_to_remove and devs_to_add:
devs_string = ' '.join([`dev` for dev in devs_to_add])
devs_to_remove_string = ' '.join([`dev` for dev in devs_to_remove])
action = 'modify'
elif devs_to_remove:
devs_string = ' '.join([`dev` for dev in devs_to_remove])
action = 'reduce'
elif devs_to_add:
devs_string = ' '.join([`dev` for dev in devs_to_add])
action = 'extend'
if action:
if module.check_mode:
changed = True
else:
if action == 'extend' or action == 'modify':
tool = 'vgextend'
### create PV
for current_dev in devs_to_add:
rc,_,err = module.run_command("pvcreate %s"%current_dev)
if rc == 0:
changed = True
else:
module.fail_json(msg="Creating physical volume '%s' failed"%current_dev, rc=rc, err=err)
else:
tool = 'vgreduce --force'
### first we add or remove PV
rc,_,err = module.run_command("%s %s %s"%(tool, vg, devs_string))
if rc == 0:
changed = True
else:
module.fail_json(msg="Unable to %s %s by %s."%(action, vg, devs_string),rc=rc,err=err)
### then if we need - remove some PV
if action == 'modify':
tool = 'vgreduce --force'
rc,_,err = module.run_command("%s %s %s"%(tool, vg, devs_to_remove_string))
if rc == 0:
changed = True
else:
module.fail_json(msg="Unable to reduce %s by %s."%(vg, devs_to_remove_string),rc=rc,err=err)
module.exit_json(changed=changed) module.exit_json(changed=changed)
# this is magic, see lib/ansible/module_common.py # this is magic, see lib/ansible/module_common.py
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment