"Fossies" - the Fresh Open Source Software Archive

Member "salt-3002.2/salt/states/lvm.py" (18 Nov 2020, 13238 Bytes) of package /linux/misc/salt-3002.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "lvm.py" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3002.1_vs_3002.2.

    1 """
    2 Management of Linux logical volumes
    3 ===================================
    4 
    5 A state module to manage LVMs
    6 
    7 .. code-block:: yaml
    8 
    9     /dev/sda:
   10       lvm.pv_present
   11 
   12     my_vg:
   13       lvm.vg_present:
   14         - devices: /dev/sda
   15 
   16     lvroot:
   17       lvm.lv_present:
   18         - vgname: my_vg
   19         - size: 10G
   20         - stripes: 5
   21         - stripesize: 8K
   22 """
   23 
   24 import os
   25 
   26 import salt.utils.path
   27 
   28 
   29 def __virtual__():
   30     """
   31     Only load the module if lvm is installed
   32     """
   33     if salt.utils.path.which("lvm"):
   34         return "lvm"
   35     return (False, "lvm command not found")
   36 
   37 
   38 def _convert_to_mb(size):
   39 
   40     size = str(size)
   41     unit = size[-1:].lower()
   42     if unit.isdigit():
   43         unit = "m"
   44     else:
   45         size = size[:-1]
   46     size = int(size)
   47 
   48     if unit == "s":
   49         target_size = size / 2048
   50     elif unit == "m":
   51         target_size = size
   52     elif unit == "g":
   53         target_size = size * 1024
   54     elif unit == "t":
   55         target_size = size * 1024 * 1024
   56     elif unit == "p":
   57         target_size = size * 1024 * 1024 * 1024
   58     else:
   59         raise salt.exceptions.ArgumentValueError("Unit {} is invalid.".format(unit))
   60     return target_size
   61 
   62 
   63 def pv_present(name, **kwargs):
   64     """
   65     Set a Physical Device to be used as an LVM Physical Volume
   66 
   67     name
   68         The device name to initialize.
   69 
   70     kwargs
   71         Any supported options to pvcreate. See
   72         :mod:`linux_lvm <salt.modules.linux_lvm>` for more details.
   73     """
   74     ret = {"changes": {}, "comment": "", "name": name, "result": True}
   75 
   76     if __salt__["lvm.pvdisplay"](name, quiet=True):
   77         ret["comment"] = "Physical Volume {} already present".format(name)
   78     elif __opts__["test"]:
   79         ret["comment"] = "Physical Volume {} is set to be created".format(name)
   80         ret["result"] = None
   81         return ret
   82     else:
   83         changes = __salt__["lvm.pvcreate"](name, **kwargs)
   84 
   85         if __salt__["lvm.pvdisplay"](name):
   86             ret["comment"] = "Created Physical Volume {}".format(name)
   87             ret["changes"]["created"] = changes
   88         else:
   89             ret["comment"] = "Failed to create Physical Volume {}".format(name)
   90             ret["result"] = False
   91     return ret
   92 
   93 
   94 def pv_absent(name):
   95     """
   96     Ensure that a Physical Device is not being used by lvm
   97 
   98     name
   99         The device name to initialize.
  100     """
  101     ret = {"changes": {}, "comment": "", "name": name, "result": True}
  102 
  103     if not __salt__["lvm.pvdisplay"](name, quiet=True):
  104         ret["comment"] = "Physical Volume {} does not exist".format(name)
  105     elif __opts__["test"]:
  106         ret["comment"] = "Physical Volume {} is set to be removed".format(name)
  107         ret["result"] = None
  108         return ret
  109     else:
  110         changes = __salt__["lvm.pvremove"](name)
  111 
  112         if __salt__["lvm.pvdisplay"](name, quiet=True):
  113             ret["comment"] = "Failed to remove Physical Volume {}".format(name)
  114             ret["result"] = False
  115         else:
  116             ret["comment"] = "Removed Physical Volume {}".format(name)
  117             ret["changes"]["removed"] = changes
  118     return ret
  119 
  120 
  121 def vg_present(name, devices=None, **kwargs):
  122     """
  123     Create an LVM Volume Group
  124 
  125     name
  126         The Volume Group name to create
  127 
  128     devices
  129         A list of devices that will be added to the Volume Group
  130 
  131     kwargs
  132         Any supported options to vgcreate. See
  133         :mod:`linux_lvm <salt.modules.linux_lvm>` for more details.
  134     """
  135     ret = {"changes": {}, "comment": "", "name": name, "result": True}
  136     if isinstance(devices, str):
  137         devices = devices.split(",")
  138 
  139     if __salt__["lvm.vgdisplay"](name, quiet=True):
  140         ret["comment"] = "Volume Group {} already present".format(name)
  141         for device in devices:
  142             realdev = os.path.realpath(device)
  143             pvs = __salt__["lvm.pvdisplay"](realdev, real=True)
  144             if pvs and pvs.get(realdev, None):
  145                 if pvs[realdev]["Volume Group Name"] == name:
  146                     ret["comment"] = "{}\n{}".format(
  147                         ret["comment"], "{} is part of Volume Group".format(device)
  148                     )
  149                 elif pvs[realdev]["Volume Group Name"] in ["", "#orphans_lvm2"]:
  150                     __salt__["lvm.vgextend"](name, device)
  151                     pvs = __salt__["lvm.pvdisplay"](realdev, real=True)
  152                     if pvs[realdev]["Volume Group Name"] == name:
  153                         ret["changes"].update({device: "added to {}".format(name)})
  154                     else:
  155                         ret["comment"] = "{}\n{}".format(
  156                             ret["comment"], "{} could not be added".format(device)
  157                         )
  158                         ret["result"] = False
  159                 else:
  160                     ret["comment"] = "{}\n{}".format(
  161                         ret["comment"],
  162                         "{} is part of {}".format(
  163                             device, pvs[realdev]["Volume Group Name"]
  164                         ),
  165                     )
  166                     ret["result"] = False
  167             else:
  168                 ret["comment"] = "{}\n{}".format(
  169                     ret["comment"], "pv {} is not present".format(device)
  170                 )
  171                 ret["result"] = False
  172     elif __opts__["test"]:
  173         ret["comment"] = "Volume Group {} is set to be created".format(name)
  174         ret["result"] = None
  175         return ret
  176     else:
  177         changes = __salt__["lvm.vgcreate"](name, devices, **kwargs)
  178 
  179         if __salt__["lvm.vgdisplay"](name):
  180             ret["comment"] = "Created Volume Group {}".format(name)
  181             ret["changes"]["created"] = changes
  182         else:
  183             ret["comment"] = "Failed to create Volume Group {}".format(name)
  184             ret["result"] = False
  185     return ret
  186 
  187 
  188 def vg_absent(name):
  189     """
  190     Remove an LVM volume group
  191 
  192     name
  193         The volume group to remove
  194     """
  195     ret = {"changes": {}, "comment": "", "name": name, "result": True}
  196 
  197     if not __salt__["lvm.vgdisplay"](name, quiet=True):
  198         ret["comment"] = "Volume Group {} already absent".format(name)
  199     elif __opts__["test"]:
  200         ret["comment"] = "Volume Group {} is set to be removed".format(name)
  201         ret["result"] = None
  202         return ret
  203     else:
  204         changes = __salt__["lvm.vgremove"](name)
  205 
  206         if not __salt__["lvm.vgdisplay"](name, quiet=True):
  207             ret["comment"] = "Removed Volume Group {}".format(name)
  208             ret["changes"]["removed"] = changes
  209         else:
  210             ret["comment"] = "Failed to remove Volume Group {}".format(name)
  211             ret["result"] = False
  212     return ret
  213 
  214 
  215 def lv_present(
  216     name,
  217     vgname=None,
  218     size=None,
  219     extents=None,
  220     snapshot=None,
  221     pv="",
  222     thinvolume=False,
  223     thinpool=False,
  224     force=False,
  225     resizefs=False,
  226     **kwargs
  227 ):
  228     """
  229     Ensure that a Logical Volume is present, creating it if absent.
  230 
  231     name
  232         The name of the Logical Volume
  233 
  234     vgname
  235         The name of the Volume Group on which the Logical Volume resides
  236 
  237     size
  238         The size of the Logical Volume
  239 
  240     extents
  241         The number of logical extents allocated to the Logical Volume
  242         It can be a percentage allowed by lvcreate's syntax, in this case
  243         it will set the Logical Volume initial size and won't be resized.
  244 
  245     snapshot
  246         The name of the snapshot
  247 
  248     pv
  249         The Physical Volume to use
  250 
  251     kwargs
  252         Any supported options to lvcreate. See
  253         :mod:`linux_lvm <salt.modules.linux_lvm>` for more details.
  254 
  255     .. versionadded:: to_complete
  256 
  257     thinvolume
  258         Logical Volume is thinly provisioned
  259 
  260     thinpool
  261         Logical Volume is a thin pool
  262 
  263     .. versionadded:: 2018.3.0
  264 
  265     force
  266         Assume yes to all prompts
  267 
  268     .. versionadded:: 3002.0
  269 
  270     resizefs
  271         Use fsadm to resize the logical volume filesystem if needed
  272 
  273     """
  274     ret = {"changes": {}, "comment": "", "name": name, "result": True}
  275 
  276     if extents and size:
  277         ret["comment"] = "Only one of extents or size can be specified."
  278         ret["result"] = False
  279         return ret
  280 
  281     _snapshot = None
  282 
  283     if snapshot:
  284         _snapshot = name
  285         name = snapshot
  286 
  287     if thinvolume:
  288         lvpath = "/dev/{}/{}".format(vgname.split("/")[0], name)
  289     else:
  290         lvpath = "/dev/{}/{}".format(vgname, name)
  291 
  292     lv_info = __salt__["lvm.lvdisplay"](lvpath, quiet=True)
  293     lv_info = lv_info.get(lvpath)
  294 
  295     if not lv_info:
  296         if __opts__["test"]:
  297             ret["comment"] = "Logical Volume {} is set to be created".format(name)
  298             ret["result"] = None
  299             return ret
  300         else:
  301             changes = __salt__["lvm.lvcreate"](
  302                 name,
  303                 vgname,
  304                 size=size,
  305                 extents=extents,
  306                 snapshot=_snapshot,
  307                 pv=pv,
  308                 thinvolume=thinvolume,
  309                 thinpool=thinpool,
  310                 force=force,
  311                 **kwargs
  312             )
  313 
  314             if __salt__["lvm.lvdisplay"](lvpath):
  315                 ret["comment"] = "Created Logical Volume {}".format(name)
  316                 ret["changes"]["created"] = changes
  317             else:
  318                 ret["comment"] = "Failed to create Logical Volume {}. Error: {}".format(
  319                     name, changes["Output from lvcreate"]
  320                 )
  321                 ret["result"] = False
  322     else:
  323         ret["comment"] = "Logical Volume {} already present".format(name)
  324 
  325         if size or extents:
  326             old_extents = int(lv_info["Current Logical Extents Associated"])
  327             old_size_mb = _convert_to_mb(lv_info["Logical Volume Size"] + "s")
  328             if size:
  329                 size_mb = _convert_to_mb(size)
  330                 extents = old_extents
  331             else:
  332                 # ignore percentage "extents" if the logical volume already exists
  333                 if "%" in str(extents):
  334                     ret[
  335                         "comment"
  336                     ] = "Logical Volume {} already present, {} won't be resized.".format(
  337                         name, extents
  338                     )
  339                     extents = old_extents
  340                 size_mb = old_size_mb
  341 
  342             if force is False and (size_mb < old_size_mb or extents < old_extents):
  343                 ret[
  344                     "comment"
  345                 ] = "To reduce a Logical Volume option 'force' must be True."
  346                 ret["result"] = False
  347                 return ret
  348 
  349             if size_mb != old_size_mb or extents != old_extents:
  350                 if __opts__["test"]:
  351                     ret["comment"] = "Logical Volume {} is set to be resized".format(
  352                         name
  353                     )
  354                     ret["result"] = None
  355                     return ret
  356                 else:
  357                     if size:
  358                         changes = __salt__["lvm.lvresize"](
  359                             lvpath=lvpath, size=size, resizefs=resizefs, force=force
  360                         )
  361                     else:
  362                         changes = __salt__["lvm.lvresize"](
  363                             lvpath=lvpath,
  364                             extents=extents,
  365                             resizefs=resizefs,
  366                             force=force,
  367                         )
  368 
  369                     if not changes:
  370                         ret[
  371                             "comment"
  372                         ] = "Failed to resize Logical Volume. Unknown Error."
  373                         ret["result"] = False
  374 
  375                     lv_info = __salt__["lvm.lvdisplay"](lvpath, quiet=True)[lvpath]
  376                     new_size_mb = _convert_to_mb(lv_info["Logical Volume Size"] + "s")
  377                     if new_size_mb != old_size_mb:
  378                         ret["comment"] = "Resized Logical Volume {}".format(name)
  379                         ret["changes"]["resized"] = changes
  380                     else:
  381                         ret[
  382                             "comment"
  383                         ] = "Failed to resize Logical Volume {}.\nError: {}".format(
  384                             name, changes["Output from lvresize"]
  385                         )
  386                         ret["result"] = False
  387     return ret
  388 
  389 
  390 def lv_absent(name, vgname=None):
  391     """
  392     Remove a given existing Logical Volume from a named existing volume group
  393 
  394     name
  395         The Logical Volume to remove
  396 
  397     vgname
  398         The name of the Volume Group on which the Logical Volume resides
  399     """
  400     ret = {"changes": {}, "comment": "", "name": name, "result": True}
  401 
  402     lvpath = "/dev/{}/{}".format(vgname, name)
  403     if not __salt__["lvm.lvdisplay"](lvpath, quiet=True):
  404         ret["comment"] = "Logical Volume {} already absent".format(name)
  405     elif __opts__["test"]:
  406         ret["comment"] = "Logical Volume {} is set to be removed".format(name)
  407         ret["result"] = None
  408         return ret
  409     else:
  410         changes = __salt__["lvm.lvremove"](name, vgname)
  411 
  412         if not __salt__["lvm.lvdisplay"](lvpath, quiet=True):
  413             ret["comment"] = "Removed Logical Volume {}".format(name)
  414             ret["changes"]["removed"] = changes
  415         else:
  416             ret["comment"] = "Failed to remove Logical Volume {}".format(name)
  417             ret["result"] = False
  418     return ret