[Kimchi-devel] [PATCH 1/2] Implement the backend to use existing VG as storage pool

Aline Manera alinefm at linux.vnet.ibm.com
Tue Oct 27 17:13:36 UTC 2015



On 22/10/2015 22:52, Jose Ricardo Ziviani wrote:
>   - This commit implements the backend for users to create a storage pool
>     using an existing backend in the system.
>
> Signed-off-by: Jose Ricardo Ziviani <joserz at linux.vnet.ibm.com>
> ---
>   src/wok/plugins/kimchi/control/host.py       |  22 +++++
>   src/wok/plugins/kimchi/disks.py              | 123 +++++++++++++++++++++++++++
>   src/wok/plugins/kimchi/i18n.py               |   3 +
>   src/wok/plugins/kimchi/model/host.py         |  30 +++++++
>   src/wok/plugins/kimchi/model/storagepools.py |   7 +-
>   5 files changed, 184 insertions(+), 1 deletion(-)
>
> diff --git a/src/wok/plugins/kimchi/control/host.py b/src/wok/plugins/kimchi/control/host.py
> index 9fe4c0a..1fa236e 100644
> --- a/src/wok/plugins/kimchi/control/host.py
> +++ b/src/wok/plugins/kimchi/control/host.py
> @@ -42,6 +42,28 @@ class Host(Resource):
>           self.swupdate = self.generate_action_handler_task('swupdate')
>           self.swupdateprogress = SoftwareUpdateProgress(self.model)
>           self.cpuinfo = CPUInfo(self.model)
> +        self.vgs = VolumeGroups(self.model)
> +
> +    @property
> +    def data(self):
> +        return self.info
> +
> +
> +class VolumeGroups(Collection):
> +    def __init__(self, model):
> +        super(VolumeGroups, self).__init__(model)
> +        self.role_key = 'host'
> +        self.uri_fmt = "/host/vgs"
> +        self.admin_methods = ['GET']
> +        self.resource = VolumeGroup
> +
> +
> +class VolumeGroup(Resource):
> +    def __init__(self, model, id=None):
> +        super(VolumeGroup, self).__init__(model, id)
> +        self.role_key = 'host'
> +        self.uri_fmt = "/host/vgs/%s"
> +        self.admin_methods = ['GET']
>
>       @property
>       def data(self):
> diff --git a/src/wok/plugins/kimchi/disks.py b/src/wok/plugins/kimchi/disks.py
> index eb40e3a..30a52b9 100644
> --- a/src/wok/plugins/kimchi/disks.py
> +++ b/src/wok/plugins/kimchi/disks.py
> @@ -194,3 +194,126 @@ def get_partition_details(name):
>       dev['path'] = dev_path
>       dev['name'] = name
>       return dev
> +
> +
> +def vgs():
> +    """
> +    lists all volume groups in the system. All size units are in bytes.
> +
> +    [{'vgname': 'vgtest', 'size': 999653638144L, 'free': 0}]
> +    """
> +    cmd = ['vgs',
> +           '--units',
> +           'b',
> +           '--nosuffix',
> +           '--noheading',
> +           '--unbuffered',
> +           '--options',
> +           'vg_name,vg_size,vg_free']
> +
> +    proc = subprocess.Popen(cmd,
> +                            stdout=subprocess.PIPE,
> +                            stderr=subprocess.PIPE)
> +
> +    out, err = proc.communicate()
> +
> +    if proc.returncode != 0:
> +        raise OperationFailed("KCHDISKS0003E", {'err': err})
> +
> +    if not out:
> +        return []
> +
> +    # remove blank spaces and create a list of VGs
> +    vgs = map(lambda v: v.strip(), out.strip('\n').split('\n'))
> +
> +    # create a dict based on data retrieved from vgs
> +    return map(lambda l: {'vgname': l[0],
> +                          'size': long(l[1]),
> +                          'free': long(l[2])},
> +               [fields.split() for fields in vgs])
> +
> +
> +def lvs(vgname=None):
> +    """
> +    lists all logical volumes found in the system. It can be filtered by
> +    the volume group. All size units are in bytes.
> +
> +    [{'lvname': 'lva', 'path': '/dev/vgtest/lva', 'size': 12345L},
> +     {'lvname': 'lvb', 'path': '/dev/vgtest/lvb', 'size': 12345L}]
> +    """
> +    cmd = ['lvs',
> +           '--units',
> +           'b',
> +           '--nosuffix',
> +           '--noheading',
> +           '--unbuffered',
> +           '--options',
> +           'lv_name,lv_path,lv_size,vg_name']
> +
> +    proc = subprocess.Popen(cmd,
> +                            stdout=subprocess.PIPE,
> +                            stderr=subprocess.PIPE)
> +
> +    out, err = proc.communicate()
> +
> +    if proc.returncode != 0:
> +        raise OperationFailed("KCHDISKS0003E", {'err': err})
> +
> +    if not out:
> +        return []
> +
> +    # remove blank spaces and create a list of LVs filtered by vgname, if
> +    # provided
> +    lvs = filter(lambda f: vgname is None or vgname in f,
> +        map(lambda v: v.strip(), out.strip('\n').split('\n')))
> +
> +    # create a dict based on data retrieved from lvs
> +    return map(lambda l: {'lvname': l[0],
> +                          'path': l[1],
> +                          'size': long(l[2])},
> +               [fields.split() for fields in lvs])
> +
> +
> +def pvs(vgname=None):
> +    """
> +    lists all physical volumes in the system. It can be filtered by the
> +    volume group. All size units are in bytes.
> +
> +    [{'pvname': '/dev/sda3',
> +      'size': 469502001152L,
> +      'uuid': 'kkon5B-vnFI-eKHn-I5cG-Hj0C-uGx0-xqZrXI'},
> +     {'pvname': '/dev/sda2',
> +      'size': 21470642176L,
> +      'uuid': 'CyBzhK-cQFl-gWqr-fyWC-A50Y-LMxu-iHiJq4'}]
> +    """
> +    cmd = ['pvs',
> +           '--units',
> +           'b',
> +           '--nosuffix',
> +           '--noheading',
> +           '--unbuffered',
> +           '--options',
> +           'pv_name,pv_size,pv_uuid,vg_name']
> +
> +    proc = subprocess.Popen(cmd,
> +                            stdout=subprocess.PIPE,
> +                            stderr=subprocess.PIPE)
> +
> +    out, err = proc.communicate()
> +
> +    if proc.returncode != 0:
> +        raise OperationFailed("KCHDISKS0003E", {'err': err})
> +
> +    if not out:
> +        return []
> +
> +    # remove blank spaces and create a list of PVs filtered by vgname, if
> +    # provided
> +    pvs = filter(lambda f: vgname is None or vgname in f,
> +        map(lambda v: v.strip(), out.strip('\n').split('\n')))
> +
> +    # create a dict based on data retrieved from pvs
> +    return map(lambda l: {'pvname': l[0],
> +                          'size': long(l[1]),
> +                          'uuid': l[2]},
> +               [fields.split() for fields in pvs])
> diff --git a/src/wok/plugins/kimchi/i18n.py b/src/wok/plugins/kimchi/i18n.py
> index e9be6af..cc55a3a 100644
> --- a/src/wok/plugins/kimchi/i18n.py
> +++ b/src/wok/plugins/kimchi/i18n.py
> @@ -34,6 +34,7 @@ messages = {
>
>       "KCHDISKS0001E": _("Error while getting block devices. Details: %(err)s"),
>       "KCHDISKS0002E": _("Error while getting block device information for %(device)s."),
> +    "KCHDISKS0003E": _("Unable to retrieve LVM information. Details: %(err)s"),
>
>       "KCHDL0001E": _("Unable to find distro file: %(filename)s"),
>       "KCHDL0002E": _("Unable to parse distro file: %(filename)s. Make sure, it is a JSON file."),
> @@ -334,4 +335,6 @@ messages = {
>       "KCHCPUINF0002E": _("Invalid vCPU/topology combination."),
>       "KCHCPUINF0003E": _("This host (or current configuration) does not allow CPU topology."),
>
> +    "KCHLVMS0001E": _("Invalid volume group name parameter: %(name)s."),
> +
>   }
> diff --git a/src/wok/plugins/kimchi/model/host.py b/src/wok/plugins/kimchi/model/host.py
> index 9b1fc32..6705ae7 100644
> --- a/src/wok/plugins/kimchi/model/host.py
> +++ b/src/wok/plugins/kimchi/model/host.py
> @@ -293,6 +293,36 @@ class HostStatsModel(object):
>           self.host_stats['net_sent_bytes'].append(sent_bytes)
>
>
> +class VolumeGroupsModel(object):
> +    def __init__(self, **kargs):
> +        pass
> +
> +    def get_list(self):
> +        if not disks.vgs():
> +            return []

> +        #return [vg['vgname'] for vg in disks.vgs() if vg['free'] > 0L]

You can remove this line

> +        return [vg['vgname'] for vg in disks.vgs()]
> +
> +
> +class VolumeGroupModel(object):
> +    def __init__(self, **kargs):
> +        pass
> +
> +    def lookup(self, name):
> +        def _format(vg):
> +            return {'vgname': vg['vgname'],
> +                    'size': vg['size'],
> +                    'free': vg['free'],
> +                    'pvs': [pv['pvname'] for pv in disks.pvs(vg['vgname'])],
> +                    'lvs': [lv['lvname'] for lv in disks.lvs(vg['vgname'])]}
> +
> +        vgs = [_format(vg) for vg in disks.vgs() if vg['vgname'] == name]
> +        if not vgs:
> +            raise InvalidParameter("KCHLVMS0001E", {'name': name})
> +
> +        return vgs[0]
> +
> +
>   class HostStatsHistoryModel(object):
>       def __init__(self, **kargs):
>           self.history = HostStatsModel(**kargs)
> diff --git a/src/wok/plugins/kimchi/model/storagepools.py b/src/wok/plugins/kimchi/model/storagepools.py
> index db68252..07a9524 100644
> --- a/src/wok/plugins/kimchi/model/storagepools.py
> +++ b/src/wok/plugins/kimchi/model/storagepools.py
> @@ -144,6 +144,11 @@ class StoragePoolsModel(object):
>       def create(self, params):
>           task_id = None
>           conn = self.conn.get()

> +
> +        use_existing_vg = False
> +        if 'vgselect' in params and params['vgselect'] == 'existingvg':
> +            use_existing_vg = True
> +

I'd suggest to use a boolean parameter, for example, 'from_vg' to 
represent that.

Also, from the libvirt documentation 
(https://libvirt.org/storage.html#StorageBackendLogical), the user just 
needs to specify the VG name to create the pool from it.
So does it mean we can not create a logical pool from an existing VG 
with a different name?



>           try:
>               name = params['name']
>               if name == ISO_POOL_NAME:
> @@ -152,7 +157,7 @@ class StoragePoolsModel(object):
>               # The user may want to create a logical pool with the same name
>               # used before but a volume group will already exist with this name
>               # So check the volume group does not exist to create the pool
> -            if params['type'] == 'logical':
> +            if params['type'] == 'logical' and not use_existing_vg:
>                   vgdisplay_cmd = ['vgdisplay', name.encode('utf-8')]
>                   output, error, returncode = run_command(vgdisplay_cmd)
>                   # From vgdisplay error codes:




More information about the Kimchi-devel mailing list