From cd95839e4ec752609d28733b06f768cb81a1b3aa Mon Sep 17 00:00:00 2001 From: Alex Kavanagh Date: Mon, 12 Nov 2018 17:26:14 +0000 Subject: [PATCH] Fix sizing and quotas nova to lxd on unsupported backends The dir and lvm backends don't support sizing and quotas. This was made more complicated with LXD3 as "storage" became the default and the dir backend, if used, has to be set up as a storage pool. LXD3 is the default on bionic. To resolve an openstack-ansible issue and lay the ground work for nova-lxd and storage pools and the lxd charm, this patch makes resolves sending sizes and quotas for a profile root device on lvm and dir backends. Change-Id: Idba4f5f3c6015616160d85f25a658cb7e5c43652 Closes-Bug: #1698761 --- nova/tests/unit/virt/lxd/test_flavor.py | 1 - nova/virt/lxd/flavor.py | 67 ++++++++++++++----------- 2 files changed, 37 insertions(+), 31 deletions(-) diff --git a/nova/tests/unit/virt/lxd/test_flavor.py b/nova/tests/unit/virt/lxd/test_flavor.py index 40159200..59a683b5 100644 --- a/nova/tests/unit/virt/lxd/test_flavor.py +++ b/nova/tests/unit/virt/lxd/test_flavor.py @@ -132,7 +132,6 @@ class ToProfileTest(test.NoDBTestCase): 'path': '/', 'type': 'disk', 'pool': 'test_pool', - 'size': '0GB' }, } flavor.to_profile(self.client, instance, network_info, block_info) diff --git a/nova/virt/lxd/flavor.py b/nova/virt/lxd/flavor.py index 6d93e8ad..21026a45 100644 --- a/nova/virt/lxd/flavor.py +++ b/nova/virt/lxd/flavor.py @@ -83,43 +83,50 @@ def _root(instance, client, *_): """Configure the root disk.""" device = {'type': 'disk', 'path': '/'} - environment = client.host_info['environment'] - if environment['storage'] in ['btrfs', 'zfs'] or CONF.lxd.pool: - device['size'] = '{}GB'.format(instance.root_gb) - - specs = instance.flavor.extra_specs - - # Bytes and iops are not separate config options in a container - # profile - we let Bytes take priority over iops if both are set. - # Align all limits to MiB/s, which should be a sensible middle road. - if specs.get('quota:disk_read_iops_sec'): - device['limits.read'] = '{}iops'.format( - specs['quota:disk_read_iops_sec']) - if specs.get('quota:disk_write_iops_sec'): - device['limits.write'] = '{}iops'.format( - specs['quota:disk_write_iops_sec']) - - if specs.get('quota:disk_read_bytes_sec'): - device['limits.read'] = '{}MB'.format( - int(specs['quota:disk_read_bytes_sec']) // units.Mi) - if specs.get('quota:disk_write_bytes_sec'): - device['limits.write'] = '{}MB'.format( - int(specs['quota:disk_write_bytes_sec']) // units.Mi) - - minor_quota_defined = 'limits.write' in device or 'limits.read' in device - if specs.get('quota:disk_total_iops_sec') and not minor_quota_defined: - device['limits.max'] = '{}iops'.format( - specs['quota:disk_total_iops_sec']) - if specs.get('quota:disk_total_bytes_sec') and not minor_quota_defined: - device['limits.max'] = '{}MB'.format( - int(specs['quota:disk_total_bytes_sec']) // units.Mi) + # we don't do quotas if the CONF.lxd.pool is set and is dir or lvm, or if + # the environment['storage'] is dir or lvm. if CONF.lxd.pool: extensions = client.host_info.get('api_extensions', []) if 'storage' in extensions: device['pool'] = CONF.lxd.pool + storage_type = client.storage_pools.get(CONF.lxd.pool).driver else: msg = _("Host does not have storage pool support") raise exception.NovaException(msg) + else: + storage_type = client.host_info['environment']['storage'] + + if storage_type in ['btrfs', 'zfs']: + device['size'] = '{}GB'.format(instance.root_gb) + + specs = instance.flavor.extra_specs + + # Bytes and iops are not separate config options in a container + # profile - we let Bytes take priority over iops if both are set. + # Align all limits to MiB/s, which should be a sensible middle road. + if specs.get('quota:disk_read_iops_sec'): + device['limits.read'] = '{}iops'.format( + specs['quota:disk_read_iops_sec']) + if specs.get('quota:disk_write_iops_sec'): + device['limits.write'] = '{}iops'.format( + specs['quota:disk_write_iops_sec']) + + if specs.get('quota:disk_read_bytes_sec'): + device['limits.read'] = '{}MB'.format( + int(specs['quota:disk_read_bytes_sec']) // units.Mi) + if specs.get('quota:disk_write_bytes_sec'): + device['limits.write'] = '{}MB'.format( + int(specs['quota:disk_write_bytes_sec']) // units.Mi) + + minor_quota_defined = ('limits.write' in device or + 'limits.read' in device) + if specs.get('quota:disk_total_iops_sec') and not minor_quota_defined: + device['limits.max'] = '{}iops'.format( + specs['quota:disk_total_iops_sec']) + if specs.get('quota:disk_total_bytes_sec') and not minor_quota_defined: + device['limits.max'] = '{}MB'.format( + int(specs['quota:disk_total_bytes_sec']) // units.Mi) + return {'root': device}