]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
ceph-volume api.lvm convert and use extents for sizing calculations
authorAlfredo Deza <adeza@redhat.com>
Fri, 13 Jul 2018 12:55:28 +0000 (08:55 -0400)
committerAndrew Schoen <aschoen@redhat.com>
Tue, 28 Aug 2018 16:06:07 +0000 (11:06 -0500)
Signed-off-by: Alfredo Deza <adeza@redhat.com>
(cherry picked from commit 99e034d7eed9508ee016431c040e3fddca9bca69)

src/ceph-volume/ceph_volume/api/lvm.py

index cc2c1132d0eb6abaa7f7facc29b0bfc0d08de699..7525ba883d0d0bec40902c7130623e06b8fda008 100644 (file)
@@ -7,7 +7,7 @@ import logging
 import os
 import uuid
 from math import floor
-from ceph_volume import process
+from ceph_volume import process, util
 from ceph_volume.exceptions import (
     MultipleLVsError, MultipleVGsError,
     MultiplePVsError, SizeAllocationError
@@ -113,15 +113,15 @@ def sizing(device_size, parts=None, size=None):
         percentages = get_percentage(parts)
 
     if size:
-        parts = int(floor(device_size / size)) or 1
+        parts = int(device_size / size) or 1
         percentages = get_percentage(parts)
 
-    sizes = int(floor(device_size / parts)) if parts else int(floor(device_size))
+    sizes = device_size / parts if parts else int(floor(device_size))
 
     return {
         'parts': parts,
         'percentages': percentages,
-        'sizes': sizes
+        'sizes': int(sizes),
     }
 
 
@@ -291,7 +291,7 @@ def get_api_vgs():
     To normalize sizing, the units are forced in 'g' which is equivalent to
     gigabytes, which uses multiples of 1024 (as opposed to 1000)
     """
-    fields = 'vg_name,pv_count,lv_count,snap_count,vg_attr,vg_size,vg_free'
+    fields = 'vg_name,pv_count,lv_count,snap_count,vg_attr,vg_size,vg_free,vg_free_count'
     stdout, stderr, returncode = process.call(
         ['vgs', '--noheadings', '--readonly', '--units=g', '--separator=";"', '-o', fields]
     )
@@ -482,7 +482,7 @@ def remove_lv(path):
     return True
 
 
-def create_lv(name, group, size=None, tags=None):
+def create_lv(name, group, extents=None, size=None, tags=None):
     """
     Create a Logical Volume in a Volume Group. Command looks like::
 
@@ -494,6 +494,14 @@ def create_lv(name, group, size=None, tags=None):
 
         {"ceph.block_device": "/dev/ceph/osd-1"}
     """
+    if tags is None:
+        tags = {
+            "ceph.osd_id": "null",
+            "ceph.type": "null",
+            "ceph.cluster_fsid": "null",
+            "ceph.osd_fsid": "null",
+        }
+
     # XXX add CEPH_VOLUME_LVM_DEBUG to enable -vvvv on lv operations
     type_path_tag = {
         'journal': 'ceph.journal_device',
@@ -511,6 +519,14 @@ def create_lv(name, group, size=None, tags=None):
             '%s' % size,
             '-n', name, group
         ])
+    elif extents:
+        process.run([
+            'lvcreate',
+            '--yes',
+            '-l',
+            '%s' % extents,
+            '-n', name, group
+        ])
     # create the lv with all the space available, this is needed because the
     # system call is different for LVM
     else:
@@ -555,6 +571,8 @@ def create_lvs(volume_group, parts=None, size=None, name_prefix='ceph-lv'):
     :type parts: int
     :param size: Size (in gigabytes) of LVs to create, e.g. "as many 10gb LVs as possible"
     :type size: int
+    :param extents: The number of LVM extents to use to create the LV. Useful if looking to have
+    accurate LV sizes (LVM rounds sizes otherwise)
     """
     if parts is None and size is None:
         # fallback to just one part (using 100% of the vg)
@@ -569,9 +587,10 @@ def create_lvs(volume_group, parts=None, size=None, name_prefix='ceph-lv'):
     sizing = volume_group.sizing(parts=parts, size=size)
     for part in range(0, sizing['parts']):
         size = sizing['sizes']
+        extents = sizing['extents']
         lv_name = '%s-%s' % (name_prefix, uuid.uuid4())
         lvs.append(
-            create_lv(lv_name, volume_group.name, size="%sg" % size, tags=tags)
+            create_lv(lv_name, volume_group.name, extents=extents, tags=tags)
         )
     return lvs
 
@@ -916,14 +935,7 @@ class VolumeGroup(object):
             logger.exception(error_msg)
             raise RuntimeError(error_msg)
 
-        try:
-            integer = float(integer)
-        except (TypeError, ValueError):
-            logger.exception(error_msg)
-            raise RuntimeError(error_msg)
-
-        # round down the float, convert to an integer
-        return int(floor(integer))
+        return util.str_to_int(integer)
 
     @property
     def free(self):
@@ -979,7 +991,32 @@ class VolumeGroup(object):
         :raises SizeAllocationError: When requested size cannot be allocated with
         :raises ValueError: If both ``parts`` and ``size`` are given
         """
-        return sizing(self.free, parts=parts, size=size)
+        if parts is not None and size is not None:
+            raise ValueError(
+                "Cannot process sizing with both parts (%s) and size (%s)" % (parts, size)
+            )
+
+        # if size is given we need to map that to extents so that we avoid
+        # issues when trying to get this right with a size in gigabytes find
+        # the percentage first, cheating, because these values are thrown out
+        vg_free_count = util.str_to_int(self.vg_free_count)
+
+        if size:
+            extents = int(size * vg_free_count / self.free)
+            disk_sizing = sizing(self.free, size=size, parts=parts)
+        else:
+            if parts is not None:
+                # Prevent parts being 0, falling back to 1 (100% usage)
+                parts = parts or 1
+            size = int(self.free / parts)
+            extents = size * vg_free_count / self.free
+            disk_sizing = sizing(self.free, parts=parts)
+
+        extent_sizing = sizing(vg_free_count, size=extents)
+
+        disk_sizing['extents'] = int(extents)
+        disk_sizing['percentages'] = extent_sizing['percentages']
+        return disk_sizing
 
 
 class Volume(object):