Mini Shell
"""
Support for Linux LVM2
"""
import logging
import os.path
import salt.utils.path
# Set up logger
log = logging.getLogger(__name__)
# Define the module's virtual name
__virtualname__ = "lvm"
def __virtual__():
"""
Only load the module if lvm is installed
"""
if salt.utils.path.which("lvm"):
return __virtualname__
return (
False,
"The linux_lvm execution module cannot be loaded: the lvm binary is not in the"
" path.",
)
def version():
"""
Return LVM version from lvm version
CLI Example:
.. code-block:: bash
salt '*' lvm.version
"""
cmd = "lvm version"
out = __salt__["cmd.run"](cmd).splitlines()
ret = out[0].split(": ")
return ret[1].strip()
def fullversion():
"""
Return all version info from lvm version
CLI Example:
.. code-block:: bash
salt '*' lvm.fullversion
"""
ret = {}
cmd = "lvm version"
out = __salt__["cmd.run"](cmd).splitlines()
for line in out:
comps = line.split(":")
ret[comps[0].strip()] = comps[1].strip()
return ret
def pvdisplay(pvname="", real=False, quiet=False):
"""
Return information about the physical volume(s)
pvname
physical device name
real
dereference any symlinks and report the real device
.. versionadded:: 2015.8.7
quiet
if the physical volume is not present, do not show any error
CLI Examples:
.. code-block:: bash
salt '*' lvm.pvdisplay
salt '*' lvm.pvdisplay /dev/md0
"""
ret = {}
cmd = ["pvdisplay", "-c"]
if pvname:
cmd.append(pvname)
cmd_ret = __salt__["cmd.run_all"](cmd, python_shell=False, ignore_retcode=quiet)
if cmd_ret["retcode"] != 0:
return {}
out = cmd_ret["stdout"].splitlines()
for line in out:
if "is a new physical volume" not in line:
comps = line.strip().split(":")
if real:
device = os.path.realpath(comps[0])
else:
device = comps[0]
ret[device] = {
"Physical Volume Device": comps[0],
"Volume Group Name": comps[1],
"Physical Volume Size (kB)": comps[2],
"Internal Physical Volume Number": comps[3],
"Physical Volume Status": comps[4],
"Physical Volume (not) Allocatable": comps[5],
"Current Logical Volumes Here": comps[6],
"Physical Extent Size (kB)": comps[7],
"Total Physical Extents": comps[8],
"Free Physical Extents": comps[9],
"Allocated Physical Extents": comps[10],
}
if real:
ret[device]["Real Physical Volume Device"] = device
return ret
def vgdisplay(vgname="", quiet=False):
"""
Return information about the volume group(s)
vgname
volume group name
quiet
if the volume group is not present, do not show any error
CLI Examples:
.. code-block:: bash
salt '*' lvm.vgdisplay
salt '*' lvm.vgdisplay nova-volumes
"""
ret = {}
cmd = ["vgdisplay", "-c"]
if vgname:
cmd.append(vgname)
cmd_ret = __salt__["cmd.run_all"](cmd, python_shell=False, ignore_retcode=quiet)
if cmd_ret["retcode"] != 0:
return {}
out = cmd_ret["stdout"].splitlines()
for line in out:
comps = line.strip().split(":")
ret[comps[0]] = {
"Volume Group Name": comps[0],
"Volume Group Access": comps[1],
"Volume Group Status": comps[2],
"Internal Volume Group Number": comps[3],
"Maximum Logical Volumes": comps[4],
"Current Logical Volumes": comps[5],
"Open Logical Volumes": comps[6],
"Maximum Logical Volume Size": comps[7],
"Maximum Physical Volumes": comps[8],
"Current Physical Volumes": comps[9],
"Actual Physical Volumes": comps[10],
"Volume Group Size (kB)": comps[11],
"Physical Extent Size (kB)": comps[12],
"Total Physical Extents": comps[13],
"Allocated Physical Extents": comps[14],
"Free Physical Extents": comps[15],
"UUID": comps[16],
}
return ret
def lvdisplay(lvname="", quiet=False):
"""
Return information about the logical volume(s)
lvname
logical device name
quiet
if the logical volume is not present, do not show any error
CLI Examples:
.. code-block:: bash
salt '*' lvm.lvdisplay
salt '*' lvm.lvdisplay /dev/vg_myserver/root
"""
ret = {}
cmd = ["lvdisplay", "-c"]
if lvname:
cmd.append(lvname)
cmd_ret = __salt__["cmd.run_all"](cmd, python_shell=False, ignore_retcode=quiet)
if cmd_ret["retcode"] != 0:
return {}
out = cmd_ret["stdout"].splitlines()
for line in out:
comps = line.strip().split(":")
ret[comps[0]] = {
"Logical Volume Name": comps[0],
"Volume Group Name": comps[1],
"Logical Volume Access": comps[2],
"Logical Volume Status": comps[3],
"Internal Logical Volume Number": comps[4],
"Open Logical Volumes": comps[5],
"Logical Volume Size": comps[6],
"Current Logical Extents Associated": comps[7],
"Allocated Logical Extents": comps[8],
"Allocation Policy": comps[9],
"Read Ahead Sectors": comps[10],
"Major Device Number": comps[11],
"Minor Device Number": comps[12],
}
return ret
def pvcreate(devices, override=True, force=True, **kwargs):
"""
Set a physical device to be used as an LVM physical volume
override
Skip devices, if they are already LVM physical volumes
CLI Examples:
.. code-block:: bash
salt mymachine lvm.pvcreate /dev/sdb1,/dev/sdb2
salt mymachine lvm.pvcreate /dev/sdb1 dataalignmentoffset=7s
"""
if not devices:
return "Error: at least one device is required"
if isinstance(devices, str):
devices = devices.split(",")
cmd = ["pvcreate"]
if force:
cmd.append("--yes")
else:
cmd.append("-qq")
for device in devices:
if not os.path.exists(device):
return f"{device} does not exist"
if not pvdisplay(device, quiet=True):
cmd.append(device)
elif not override:
return f'Device "{device}" is already an LVM physical volume.'
if not cmd[2:]:
# All specified devices are already LVM volumes
return True
valid = (
"metadatasize",
"dataalignment",
"dataalignmentoffset",
"pvmetadatacopies",
"metadatacopies",
"metadataignore",
"restorefile",
"norestorefile",
"labelsector",
"setphysicalvolumesize",
)
no_parameter = "norestorefile"
for var in kwargs:
if kwargs[var] and var in valid:
cmd.extend([f"--{var}", kwargs[var]])
elif kwargs[var] and var in no_parameter:
cmd.append(f"--{var}")
out = __salt__["cmd.run_all"](cmd, python_shell=False)
if out.get("retcode"):
return out.get("stderr")
# Verify pvcreate was successful
for device in devices:
if not pvdisplay(device):
return f'Device "{device}" was not affected.'
return True
def pvremove(devices, override=True, force=True):
"""
Remove a physical device being used as an LVM physical volume
override
Skip devices, if they are already not used as LVM physical volumes
CLI Examples:
.. code-block:: bash
salt mymachine lvm.pvremove /dev/sdb1,/dev/sdb2
"""
if isinstance(devices, str):
devices = devices.split(",")
cmd = ["pvremove"]
if force:
cmd.append("--yes")
else:
cmd.append("-qq")
for device in devices:
if pvdisplay(device):
cmd.append(device)
elif not override:
return f"{device} is not a physical volume"
if not cmd[2:]:
# Nothing to do
return True
out = __salt__["cmd.run_all"](cmd, python_shell=False)
if out.get("retcode"):
return out.get("stderr")
# Verify pvremove was successful
for device in devices:
if pvdisplay(device, quiet=True):
return f'Device "{device}" was not affected.'
return True
def vgcreate(vgname, devices, force=False, **kwargs):
"""
Create an LVM volume group
CLI Examples:
.. code-block:: bash
salt mymachine lvm.vgcreate my_vg /dev/sdb1,/dev/sdb2
salt mymachine lvm.vgcreate my_vg /dev/sdb1 clustered=y
"""
if not vgname or not devices:
return "Error: vgname and device(s) are both required"
if isinstance(devices, str):
devices = devices.split(",")
cmd = ["vgcreate", vgname]
for device in devices:
cmd.append(device)
if force:
cmd.append("--yes")
else:
cmd.append("-qq")
valid = (
"addtag",
"alloc",
"autobackup",
"clustered",
"maxlogicalvolumes",
"maxphysicalvolumes",
"metadatatype",
"vgmetadatacopies",
"metadatacopies",
"physicalextentsize",
"zero",
)
for var in kwargs:
if kwargs[var] and var in valid:
cmd.append(f"--{var}")
cmd.append(kwargs[var])
cmd_ret = __salt__["cmd.run_all"](cmd, python_shell=False)
if cmd_ret.get("retcode"):
out = cmd_ret.get("stderr").strip()
else:
out = f'Volume group "{vgname}" successfully created'
vgdata = vgdisplay(vgname)
vgdata["Output from vgcreate"] = out
return vgdata
def vgextend(vgname, devices, force=False):
"""
Add physical volumes to an LVM volume group
CLI Examples:
.. code-block:: bash
salt mymachine lvm.vgextend my_vg /dev/sdb1,/dev/sdb2
salt mymachine lvm.vgextend my_vg /dev/sdb1
"""
if not vgname or not devices:
return "Error: vgname and device(s) are both required"
if isinstance(devices, str):
devices = devices.split(",")
cmd = ["vgextend", vgname]
if force:
cmd.append("--yes")
else:
cmd.append("-qq")
for device in devices:
cmd.append(device)
cmd_ret = __salt__["cmd.run_all"](cmd, python_shell=False)
if cmd_ret.get("retcode"):
out = cmd_ret.get("stderr").strip()
else:
out = f'Volume group "{vgname}" successfully extended'
vgdata = {"Output from vgextend": out}
return vgdata
def lvcreate(
lvname,
vgname,
size=None,
extents=None,
snapshot=None,
pv=None,
thinvolume=False,
thinpool=False,
force=False,
**kwargs,
):
"""
Create a new logical volume, with option for which physical volume to be used
CLI Examples:
.. code-block:: bash
salt '*' lvm.lvcreate new_volume_name vg_name size=10G
salt '*' lvm.lvcreate new_volume_name vg_name extents=100 pv=/dev/sdb
salt '*' lvm.lvcreate new_snapshot vg_name snapshot=volume_name size=3G
.. versionadded:: 0.12.0
Support for thin pools and thin volumes
CLI Examples:
.. code-block:: bash
salt '*' lvm.lvcreate new_thinpool_name vg_name size=20G thinpool=True
salt '*' lvm.lvcreate new_thinvolume_name vg_name/thinpool_name size=10G thinvolume=True
"""
if size and extents:
return "Error: Please specify only one of size or extents"
if thinvolume and thinpool:
return "Error: Please set only one of thinvolume or thinpool to True"
valid = (
"activate",
"chunksize",
"contiguous",
"discards",
"stripes",
"stripesize",
"minor",
"persistent",
"mirrors",
"nosync",
"noudevsync",
"monitor",
"ignoremonitoring",
"permission",
"poolmetadatasize",
"readahead",
"regionsize",
"type",
"virtualsize",
"zero",
)
no_parameter = (
"nosync",
"noudevsync",
"ignoremonitoring",
"thin",
)
extra_arguments = []
if kwargs:
for k, v in kwargs.items():
if k in no_parameter:
extra_arguments.append(f"--{k}")
elif k in valid:
extra_arguments.extend([f"--{k}", f"{v}"])
cmd = [salt.utils.path.which("lvcreate")]
if thinvolume:
cmd.extend(["--thin", "-n", lvname])
elif thinpool:
cmd.extend(["--thinpool", lvname])
else:
cmd.extend(["-n", lvname])
if snapshot:
cmd.extend(["-s", f"{vgname}/{snapshot}"])
else:
cmd.append(vgname)
if size and thinvolume:
cmd.extend(["-V", f"{size}"])
elif extents and thinvolume:
return "Error: Thin volume size cannot be specified as extents"
elif size:
cmd.extend(["-L", f"{size}"])
elif extents:
cmd.extend(["-l", f"{extents}"])
else:
return "Error: Either size or extents must be specified"
if pv:
cmd.append(pv)
if extra_arguments:
cmd.extend(extra_arguments)
if force:
cmd.append("--yes")
else:
cmd.append("-qq")
cmd_ret = __salt__["cmd.run_all"](cmd, python_shell=False)
if cmd_ret.get("retcode"):
out = cmd_ret.get("stderr").strip()
else:
out = f'Logical volume "{lvname}" created.'
lvdev = f"/dev/{vgname}/{lvname}"
lvdata = lvdisplay(lvdev)
lvdata["Output from lvcreate"] = out
return lvdata
def vgremove(vgname, force=True):
"""
Remove an LVM volume group
CLI Examples:
.. code-block:: bash
salt mymachine lvm.vgremove vgname
salt mymachine lvm.vgremove vgname force=True
"""
cmd = ["vgremove", vgname]
if force:
cmd.append("--yes")
else:
cmd.append("-qq")
cmd_ret = __salt__["cmd.run_all"](cmd, python_shell=False)
if cmd_ret.get("retcode"):
out = cmd_ret.get("stderr").strip()
else:
out = f'Volume group "{vgname}" successfully removed'
return out
def lvremove(lvname, vgname, force=True):
"""
Remove a given existing logical volume from a named existing volume group
CLI Example:
.. code-block:: bash
salt '*' lvm.lvremove lvname vgname force=True
"""
cmd = ["lvremove", f"{vgname}/{lvname}"]
if force:
cmd.append("--yes")
else:
cmd.append("-qq")
cmd_ret = __salt__["cmd.run_all"](cmd, python_shell=False)
if cmd_ret.get("retcode"):
out = cmd_ret.get("stderr").strip()
else:
out = f'Logical volume "{lvname}" successfully removed'
return out
def lvresize(size=None, lvpath=None, extents=None, force=False, resizefs=False):
"""
Resize a logical volume to specific size.
CLI Examples:
.. code-block:: bash
salt '*' lvm.lvresize +12M /dev/mapper/vg1-test
salt '*' lvm.lvresize lvpath=/dev/mapper/vg1-test extents=+100%FREE
"""
if size and extents:
log.error("Error: Please specify only one of size or extents")
return {}
cmd = ["lvresize"]
if force:
cmd.append("--force")
else:
cmd.append("-qq")
if resizefs:
cmd.append("--resizefs")
if size:
cmd.extend(["-L", f"{size}"])
elif extents:
cmd.extend(["-l", f"{extents}"])
else:
log.error("Error: Either size or extents must be specified")
return {}
cmd.append(lvpath)
cmd_ret = __salt__["cmd.run_all"](cmd, python_shell=False)
if cmd_ret.get("retcode"):
out = cmd_ret.get("stderr").strip()
else:
out = f'Logical volume "{lvpath}" successfully resized.'
return {"Output from lvresize": out}
def lvextend(size=None, lvpath=None, extents=None, force=False, resizefs=False):
"""
Increase a logical volume to specific size.
CLI Examples:
.. code-block:: bash
salt '*' lvm.lvextend +12M /dev/mapper/vg1-test
salt '*' lvm.lvextend lvpath=/dev/mapper/vg1-test extents=+100%FREE
"""
if size and extents:
log.error("Error: Please specify only one of size or extents")
return {}
cmd = ["lvextend"]
if force:
cmd.append("--yes")
else:
cmd.append("-qq")
if resizefs:
cmd.append("--resizefs")
if size:
cmd.extend(["-L", f"{size}"])
elif extents:
cmd.extend(["-l", f"{extents}"])
else:
log.error("Error: Either size or extents must be specified")
return {}
cmd.append(lvpath)
cmd_ret = __salt__["cmd.run_all"](cmd, python_shell=False)
if cmd_ret.get("retcode"):
out = cmd_ret.get("stderr").strip()
else:
out = f'Logical volume "{lvpath}" successfully extended.'
return {"Output from lvextend": out}
def pvresize(devices, override=True, force=True):
"""
Resize a LVM physical volume to the physical device size
override
Skip devices, if they are already not used as LVM physical volumes
CLI Examples:
.. code-block:: bash
salt mymachine lvm.pvresize /dev/sdb1,/dev/sdb2
"""
if isinstance(devices, str):
devices = devices.split(",")
cmd = ["pvresize"]
if force:
cmd.append("--yes")
else:
cmd.append("-qq")
for device in devices:
if pvdisplay(device):
cmd.append(device)
elif not override:
return f"{device} is not a physical volume"
if not cmd[2:]:
# Nothing to do
return True
out = __salt__["cmd.run_all"](cmd, python_shell=False)
if out.get("retcode"):
return out.get("stderr")
return True
Zerion Mini Shell 1.0