Merge "Enhancement for Controller Filesystem Extension"

This commit is contained in:
Zuul 2018-11-30 17:34:10 +00:00 committed by Gerrit Code Review
commit e60861bdd5
7 changed files with 66 additions and 154 deletions

View File

@ -23,6 +23,7 @@ except Exception:
import argparse import argparse
import copy import copy
import dateutil import dateutil
import math
import os import os
import prettytable import prettytable
import re import re
@ -749,10 +750,18 @@ def extract_keypairs(args):
return attributes return attributes
# Convert size from BYTE to KiB, MiB, GiB, TiB, PiB def size_unit_conversion(size, step):
# 1 - KiB, 2 - MiB, 3 - GiB, 4 - TiB, 5 - PiB """
def convert_size_from_bytes(bytes, type): This function converts size from a smaller unit (e.g. KiB)
return '%.2f' % (float(bytes) / (1024 ** type)) to a larger unit (e.g. GiB).
:param size: Size value to convert from one unit to another
:param step: Power of 2^10. e.g. From Byte to MiB is 2 steps.
From MiB to GiB is 1 step.
:returns: The return value is a float with 3 digits after
the decimal point.
"""
return math.floor(float(size) / (1024 ** step) * 1000) / 1000.0
def _get_system_info(cc): def _get_system_info(cc):

View File

@ -9,7 +9,6 @@
# All Rights Reserved. # All Rights Reserved.
# #
from cgtsclient.common import constants
from cgtsclient.common import utils from cgtsclient.common import utils
from cgtsclient import exc from cgtsclient import exc
from cgtsclient.v1 import ihost as ihost_utils from cgtsclient.v1 import ihost as ihost_utils
@ -20,17 +19,20 @@ from oslo_serialization import jsonutils
def _print_ilvg_show(ilvg): def _print_ilvg_show(ilvg):
labels = ['lvm_vg_name', 'vg_state', 'uuid', 'ihost_uuid', 'lvm_vg_access', labels = ['lvm_vg_name', 'vg_state', 'uuid', 'ihost_uuid', 'lvm_vg_access',
'lvm_max_lv', 'lvm_cur_lv', 'lvm_max_pv', 'lvm_cur_pv', 'lvm_max_lv', 'lvm_cur_lv', 'lvm_max_pv', 'lvm_cur_pv',
'lvm_vg_size_gib', 'lvm_vg_total_pe', 'lvm_vg_free_pe', 'created_at', 'lvm_vg_size_gib', 'lvm_vg_avail_size_gib', 'lvm_vg_total_pe',
'updated_at', 'parameters'] 'lvm_vg_free_pe', 'created_at', 'updated_at', 'parameters']
fields = ['lvm_vg_name', 'vg_state', 'uuid', 'ihost_uuid', 'lvm_vg_access', fields = ['lvm_vg_name', 'vg_state', 'uuid', 'ihost_uuid', 'lvm_vg_access',
'lvm_max_lv', 'lvm_cur_lv', 'lvm_max_pv', 'lvm_cur_pv', 'lvm_max_lv', 'lvm_cur_lv', 'lvm_max_pv', 'lvm_cur_pv',
'lvm_vg_size', 'lvm_vg_total_pe', 'lvm_vg_free_pe', 'created_at', 'lvm_vg_size', 'lvm_vg_avail_size', 'lvm_vg_total_pe',
'updated_at'] 'lvm_vg_free_pe', 'created_at', 'updated_at']
# convert size from Byte to GiB # convert size from Byte to GiB
ilvg.lvm_vg_size = utils.convert_size_from_bytes(ilvg.lvm_vg_size, ilvg.lvm_vg_avail_size = \
constants.GiB) utils.size_unit_conversion(ilvg.lvm_vg_avail_size, 3)
# convert size from Byte to GiB
ilvg.lvm_vg_size = utils.size_unit_conversion(ilvg.lvm_vg_size, 3)
data = [(f, getattr(ilvg, f, '')) for f in fields] data = [(f, getattr(ilvg, f, '')) for f in fields]
@ -89,13 +91,18 @@ def do_host_lvg_list(cc, args):
lvg.vg_state = _adjust_state_data(lvg.lvm_vg_name, lvg.vg_state) lvg.vg_state = _adjust_state_data(lvg.lvm_vg_name, lvg.vg_state)
# convert size from Byte to GiB # convert size from Byte to GiB
lvg.lvm_vg_size = utils.convert_size_from_bytes(lvg.lvm_vg_size, lvg.lvm_vg_avail_size = \
constants.GiB) utils.size_unit_conversion(lvg.lvm_vg_avail_size, 3)
# convert size from Byte to GiB
lvg.lvm_vg_size = \
utils.size_unit_conversion(lvg.lvm_vg_size, 3)
field_labels = ['UUID', 'LVG Name', 'State', 'Access', field_labels = ['UUID', 'LVG Name', 'State', 'Access',
'Size (GiB)', 'Current PVs', 'Current LVs'] 'Total Size (GiB)', 'Avail Size (GiB)',
'Current PVs', 'Current LVs']
fields = ['uuid', 'lvm_vg_name', 'vg_state', 'lvm_vg_access', fields = ['uuid', 'lvm_vg_name', 'vg_state', 'lvm_vg_access',
'lvm_vg_size', 'lvm_cur_pv', 'lvm_cur_lv'] 'lvm_vg_size', 'lvm_vg_avail_size', 'lvm_cur_pv', 'lvm_cur_lv']
utils.print_list(ilvgs, fields, field_labels, sortby=0) utils.print_list(ilvgs, fields, field_labels, sortby=0)

View File

@ -253,22 +253,10 @@ def _check_controller_multi_fs(controller_fs_new_list,
LOG.info("_check_controller__multi_fs ceph_mon_gib_new = %s" % ceph_mon_gib_new) LOG.info("_check_controller__multi_fs ceph_mon_gib_new = %s" % ceph_mon_gib_new)
device_path_ctrl0 = None cgtsvg_max_free_GiB = _get_controller_cgtsvg_limit()
device_path_ctrl1 = None
if ceph_mons: LOG.info("_check_controller_multi_fs cgtsvg_max_free_GiB = %s " %
for ceph_mon in ceph_mons: cgtsvg_max_free_GiB)
ihost = pecan.request.dbapi.ihost_get(ceph_mon.forihostid)
if ihost.hostname == constants.CONTROLLER_0_HOSTNAME:
device_path_ctrl0 = ceph_mon.device_path
if ihost.hostname == constants.CONTROLLER_1_HOSTNAME:
device_path_ctrl1 = ceph_mon.device_path
rootfs_max_GiB, cgtsvg_max_free_GiB = \
_get_controller_fs_limit(device_path_ctrl0, device_path_ctrl1)
LOG.info("_check_controller_multi_fs rootfs_max_GiB = %s cgtsvg_max_free_GiB = %s " %
(rootfs_max_GiB, cgtsvg_max_free_GiB))
_check_relative_controller_multi_fs(controller_fs_new_list) _check_relative_controller_multi_fs(controller_fs_new_list)
@ -392,19 +380,11 @@ def _check_controller_state():
return True return True
def _get_controller_fs_limit(device_path_ctrl0, device_path_ctrl1): def _get_controller_cgtsvg_limit():
"""Calculate space for controller rootfs plus ceph_mon_dev """Calculate space for controller fs
returns: fs_max_GiB returns: cgtsvg_max_free_GiB
cgtsvg_max_free_GiB
""" """
reserved_space = constants.CONTROLLER_ROOTFS_RESERVED
max_disk_size_controller0 = 0
max_disk_size_controller1 = 0
idisks0 = None
idisks1 = None
cgtsvg0_free_mib = 0 cgtsvg0_free_mib = 0
cgtsvg1_free_mib = 0 cgtsvg1_free_mib = 0
cgtsvg_max_free_GiB = 0 cgtsvg_max_free_GiB = 0
@ -413,8 +393,6 @@ def _get_controller_fs_limit(device_path_ctrl0, device_path_ctrl1):
constants.CONTROLLER) constants.CONTROLLER)
for chost in chosts: for chost in chosts:
if chost.hostname == constants.CONTROLLER_0_HOSTNAME: if chost.hostname == constants.CONTROLLER_0_HOSTNAME:
idisks0 = pecan.request.dbapi.idisk_get_by_ihost(chost.uuid)
ipvs = pecan.request.dbapi.ipv_get_by_ihost(chost.uuid) ipvs = pecan.request.dbapi.ipv_get_by_ihost(chost.uuid)
for ipv in ipvs: for ipv in ipvs:
if (ipv.lvm_vg_name == constants.LVG_CGTS_VG and if (ipv.lvm_vg_name == constants.LVG_CGTS_VG and
@ -433,8 +411,6 @@ def _get_controller_fs_limit(device_path_ctrl0, device_path_ctrl1):
break break
else: else:
idisks1 = pecan.request.dbapi.idisk_get_by_ihost(chost.uuid)
ipvs = pecan.request.dbapi.ipv_get_by_ihost(chost.uuid) ipvs = pecan.request.dbapi.ipv_get_by_ihost(chost.uuid)
for ipv in ipvs: for ipv in ipvs:
if (ipv.lvm_vg_name == constants.LVG_CGTS_VG and if (ipv.lvm_vg_name == constants.LVG_CGTS_VG and
@ -452,59 +428,9 @@ def _get_controller_fs_limit(device_path_ctrl0, device_path_ctrl1):
ilvg.lvm_vg_total_pe)) / (1024 * 1024) ilvg.lvm_vg_total_pe)) / (1024 * 1024)
break break
LOG.info("_get_controller_fs_limit cgtsvg0_free_mib=%s, " LOG.info("_get_controller_cgtsvg_limit cgtsvg0_free_mib=%s, "
"cgtsvg1_free_mib=%s" % (cgtsvg0_free_mib, cgtsvg1_free_mib)) "cgtsvg1_free_mib=%s" % (cgtsvg0_free_mib, cgtsvg1_free_mib))
# relies on the sizes of the partitions allocated in
# cgcs/common-bsp/files/TEMPLATE_controller_disk.add.
for chost in chosts:
if chost.hostname == constants.CONTROLLER_0_HOSTNAME and idisks0:
idisks = idisks0
elif chost.hostname == constants.CONTROLLER_1_HOSTNAME and idisks1:
idisks = idisks1
else:
LOG.error("SYS_I unexpected chost uuid %s hostname %s" %
(chost.uuid, chost.hostname))
continue
# find the largest disk for each controller
for idisk in idisks:
capabilities = idisk['capabilities']
if 'stor_function' in capabilities:
if capabilities['stor_function'] == 'rootfs':
disk_size_gib = idisk.size_mib / 1024
if chost.hostname == constants.CONTROLLER_0_HOSTNAME:
if disk_size_gib > max_disk_size_controller0:
max_disk_size_controller0 = disk_size_gib
else:
if disk_size_gib > max_disk_size_controller1:
max_disk_size_controller1 = disk_size_gib
if (device_path_ctrl0 == idisk.device_path and
chost.hostname == constants.CONTROLLER_0_HOSTNAME):
disk_size_gib = idisk.size_mib / 1024
max_disk_size_controller0 += disk_size_gib
elif (device_path_ctrl1 == idisk.device_path and
chost.hostname == constants.CONTROLLER_1_HOSTNAME):
disk_size_gib = idisk.size_mib / 1024
max_disk_size_controller1 += disk_size_gib
if max_disk_size_controller0 > 0 and max_disk_size_controller1 > 0:
minimax = min(max_disk_size_controller0, max_disk_size_controller1)
LOG.info("_get_controller_fs_limit minimax=%s" % minimax)
fs_max_GiB = minimax - reserved_space
elif max_disk_size_controller1 > 0:
fs_max_GiB = max_disk_size_controller1 - reserved_space
else:
fs_max_GiB = max_disk_size_controller0 - reserved_space
LOG.info("SYS_I filesystem limits max_disk_size_controller0=%s, "
"max_disk_size_controller1=%s, reserved_space=%s, fs_max_GiB=%s" %
(max_disk_size_controller0, max_disk_size_controller1,
reserved_space, int(fs_max_GiB)))
if cgtsvg0_free_mib > 0 and cgtsvg1_free_mib > 0: if cgtsvg0_free_mib > 0 and cgtsvg1_free_mib > 0:
cgtsvg_max_free_GiB = min(cgtsvg0_free_mib, cgtsvg1_free_mib) / 1024 cgtsvg_max_free_GiB = min(cgtsvg0_free_mib, cgtsvg1_free_mib) / 1024
LOG.info("min of cgtsvg0_free_mib=%s and cgtsvg1_free_mib=%s is " LOG.info("min of cgtsvg0_free_mib=%s and cgtsvg1_free_mib=%s is "
@ -515,37 +441,11 @@ def _get_controller_fs_limit(device_path_ctrl0, device_path_ctrl1):
else: else:
cgtsvg_max_free_GiB = cgtsvg0_free_mib / 1024 cgtsvg_max_free_GiB = cgtsvg0_free_mib / 1024
cgtsvg_max_free_GiB -= constants.CFS_RESIZE_BUFFER_GIB
LOG.info("SYS_I filesystem limits cgtsvg0_free_mib=%s, " LOG.info("SYS_I filesystem limits cgtsvg0_free_mib=%s, "
"cgtsvg1_free_mib=%s, cgtsvg_max_free_GiB=%s" "cgtsvg1_free_mib=%s, cgtsvg_max_free_GiB=%s"
% (cgtsvg0_free_mib, cgtsvg1_free_mib, cgtsvg_max_free_GiB)) % (cgtsvg0_free_mib, cgtsvg1_free_mib, cgtsvg_max_free_GiB))
return fs_max_GiB, cgtsvg_max_free_GiB return cgtsvg_max_free_GiB
def get_controller_fs_limit():
ceph_mons = pecan.request.dbapi.ceph_mon_get_list()
if ceph_mons:
ceph_mon_gib_new = ceph_mons[0].ceph_mon_gib
else:
ceph_mon_gib_new = 0
LOG.debug("_check_controller_fs ceph_mon_gib_new = %s" % ceph_mon_gib_new)
device_path_ctrl0 = None
device_path_ctrl1 = None
if ceph_mons:
for ceph_mon in ceph_mons:
ihost = pecan.request.dbapi.ihost_get(ceph_mon.forihostid)
if ihost.hostname == constants.CONTROLLER_0_HOSTNAME:
device_path_ctrl0 = ceph_mon.device_path
if ihost.hostname == constants.CONTROLLER_1_HOSTNAME:
device_path_ctrl1 = ceph_mon.device_path
return _get_controller_fs_limit(device_path_ctrl0, device_path_ctrl1)
def _check_controller_fs(controller_fs_new=None, def _check_controller_fs(controller_fs_new=None,
@ -569,23 +469,10 @@ def _check_controller_fs(controller_fs_new=None,
else: else:
cgtsvg_growth_gib = ceph_mon_gib_new cgtsvg_growth_gib = ceph_mon_gib_new
device_path_ctrl0 = None cgtsvg_max_free_GiB = _get_controller_cgtsvg_limit()
device_path_ctrl1 = None
if ceph_mons:
for ceph_mon in ceph_mons:
ihost = pecan.request.dbapi.ihost_get(ceph_mon.forihostid)
if ihost.hostname == constants.CONTROLLER_0_HOSTNAME:
device_path_ctrl0 = ceph_mon.device_path
if ihost.hostname == constants.CONTROLLER_1_HOSTNAME:
device_path_ctrl1 = ceph_mon.device_path
rootfs_max_GiB, cgtsvg_max_free_GiB = \
_get_controller_fs_limit(device_path_ctrl0, device_path_ctrl1)
LOG.info("_check_controller_fs ceph_mon_gib_new = %s" % ceph_mon_gib_new) LOG.info("_check_controller_fs ceph_mon_gib_new = %s" % ceph_mon_gib_new)
LOG.info("_check_controller_fs cgtsvg_growth_gib = %s" % cgtsvg_growth_gib) LOG.info("_check_controller_fs cgtsvg_growth_gib = %s" % cgtsvg_growth_gib)
LOG.info("_check_controller_fs rootfs_max_GiB = %s" % rootfs_max_GiB)
LOG.info("_check_controller_fs cgtsvg_max_free_GiB = %s" % cgtsvg_max_free_GiB) LOG.info("_check_controller_fs cgtsvg_max_free_GiB = %s" % cgtsvg_max_free_GiB)
_check_relative_controller_fs(controller_fs_new, controller_fs_list) _check_relative_controller_fs(controller_fs_new, controller_fs_list)

View File

@ -23,6 +23,7 @@ import ast
import cgi import cgi
import copy import copy
import json import json
import math
import os import os
import re import re
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
@ -3872,17 +3873,13 @@ class HostController(rest.RestController):
str(standby_controller_allocated_space)) str(standby_controller_allocated_space))
if (active_controller_used > standby_controller_allocated_space): if (active_controller_used > standby_controller_allocated_space):
# Since we allocate space that is measured in GiB, the human # Round up the needed space from float to integer
# readable information shown in case of an error should also needed_space = math.ceil(float(
# be in GiB. We add a 2GB buffer (the same used when changing
# filesystem sizes) to ensure no rounding errors
needed_space = (float(
active_controller_used - active_controller_used -
standby_controller_allocated_space) / (1024 ** 3) + standby_controller_allocated_space) / (1024 ** 3))
constants.CFS_RESIZE_BUFFER_GIB)
msg = _("Standby controller does not have enough space allocated to " msg = _("Standby controller does not have enough space allocated to "
"%(vg_name)s volume-group in order to create all filesystems. " "%(vg_name)s volume-group in order to create all filesystems. "
"Please assign an extra %(needed).2f GB to the volume group.") % { "Please assign an extra %(needed)d GB to the volume group.") % {
'vg_name': constants.LVG_CGTS_VG, 'needed': needed_space} 'vg_name': constants.LVG_CGTS_VG, 'needed': needed_space}
raise wsme.exc.ClientSideError(msg) raise wsme.exc.ClientSideError(msg)

View File

@ -92,7 +92,10 @@ class LVG(base.APIBase):
"LVM Volume Group's current physical volumes" "LVM Volume Group's current physical volumes"
lvm_vg_size = int lvm_vg_size = int
"LVM Volume Group's size" "LVM Volume Group's total size"
lvm_vg_avail_size = int
"LVM Volume Group's available size. API only attribute"
lvm_vg_total_pe = int lvm_vg_total_pe = int
"LVM Volume Group's total PEs" "LVM Volume Group's total PEs"
@ -124,6 +127,9 @@ class LVG(base.APIBase):
if not self.uuid: if not self.uuid:
self.uuid = uuidutils.generate_uuid() self.uuid = uuidutils.generate_uuid()
self.fields.append('lvm_vg_avail_size')
setattr(self, 'lvm_vg_avail_size', kwargs.get('lvm_vg_avail_size', 0))
@classmethod @classmethod
def convert_with_links(cls, rpc_lvg, expand=True): def convert_with_links(cls, rpc_lvg, expand=True):
lvg = LVG(**rpc_lvg.as_dict()) lvg = LVG(**rpc_lvg.as_dict())
@ -132,11 +138,22 @@ class LVG(base.APIBase):
'lvm_vg_uuid', 'lvm_vg_access', 'lvm_vg_uuid', 'lvm_vg_access',
'lvm_max_lv', 'lvm_cur_lv', 'lvm_max_lv', 'lvm_cur_lv',
'lvm_max_pv', 'lvm_cur_pv', 'lvm_max_pv', 'lvm_cur_pv',
'lvm_vg_size', 'lvm_vg_total_pe', 'lvm_vg_size', 'lvm_vg_avail_size',
'lvm_vg_total_pe',
'lvm_vg_free_pe', 'capabilities', 'lvm_vg_free_pe', 'capabilities',
'created_at', 'updated_at', 'created_at', 'updated_at',
'ihost_uuid', 'forihostid']) 'ihost_uuid', 'forihostid'])
# To calculate Volume Group's available size in byte:
# lvm_vg_size is Volume Group's total size in byte
# lvm_vg_free_pe is Volume Group's free Physical Extents
# lvm_vg_total_pe is Volume Group's total Physical Extents
if lvg.lvm_vg_total_pe > 0:
lvg.lvm_vg_avail_size = \
lvg.lvm_vg_size * lvg.lvm_vg_free_pe / lvg.lvm_vg_total_pe
else:
lvg.lvm_vg_avail_size = 0
# never expose the ihost_id attribute, allow exposure for now # never expose the ihost_id attribute, allow exposure for now
lvg.forihostid = wtypes.Unset lvg.forihostid = wtypes.Unset
lvg.links = [link.Link.make_link('self', pecan.request.host_url, lvg.links = [link.Link.make_link('self', pecan.request.host_url,
@ -466,6 +483,7 @@ def _set_defaults(lvg):
'lvm_max_pv': 0, 'lvm_max_pv': 0,
'lvm_cur_pv': 0, 'lvm_cur_pv': 0,
'lvm_vg_size': 0, 'lvm_vg_size': 0,
'lvm_vg_avail_size': 0,
'lvm_vg_total_pe': 0, 'lvm_vg_total_pe': 0,
'lvm_vg_free_pe': 0, 'lvm_vg_free_pe': 0,
'capabilities': {}, 'capabilities': {},

View File

@ -435,12 +435,6 @@ SB_CONFIGURATION_TIMEOUT = 1200
# Storage: Minimum number of monitors # Storage: Minimum number of monitors
MIN_STOR_MONITORS = 2 MIN_STOR_MONITORS = 2
# Storage: reserved space for calculating controller rootfs limit
CONTROLLER_ROOTFS_RESERVED = 38
# Controller filesystem reserved space to ensure no rounding errors
CFS_RESIZE_BUFFER_GIB = 2
BACKUP_OVERHEAD = 20 BACKUP_OVERHEAD = 20
# Suffix used in LVM volume name to indicate that the # Suffix used in LVM volume name to indicate that the

View File

@ -387,7 +387,7 @@ class StorageBackendConfig(object):
return return
# Check if there is enough space available # Check if there is enough space available
rootfs_max_GiB, cgtsvg_max_free_GiB = controller_fs_api.get_controller_fs_limit() cgtsvg_max_free_GiB = controller_fs_api._get_controller_cgtsvg_limit()
args = {'avail': cgtsvg_max_free_GiB, args = {'avail': cgtsvg_max_free_GiB,
'min': constants.DEFAULT_SMALL_IMG_CONVERSION_STOR_SIZE, 'min': constants.DEFAULT_SMALL_IMG_CONVERSION_STOR_SIZE,
'lvg': constants.LVG_CGTS_VG} 'lvg': constants.LVG_CGTS_VG}