Files
charm-nova-compute/unit_tests/test_nova_compute_contexts.py
Edward Hope-Morley e80e7163bc Do not render console config for s390x
Remote console access protocols such as spice,
novnc etc are not supported on s390x so do
not enable them in nova.conf as this will cause
Nova to error.

Change-Id: I84891dcb61fa2733f20b5a0586b1dfebe7ed1ff6
Closes-Bug: #2063190
2024-09-23 12:53:45 +01:00

1780 lines
73 KiB
Python

# Copyright 2016 Canonical Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import platform
from unittest.mock import patch
from test_utils import CharmTestCase
import nova_compute_context as context
TO_PATCH = [
'apt_install',
'filter_installed_packages',
'kv',
'relation_ids',
'relation_get',
'related_units',
'service_name',
'config',
'log',
'_save_flag_file',
'lsb_release',
'os_release',
'get_relation_ip',
]
NEUTRON_CONTEXT = {
'network_manager': 'neutron',
'quantum_auth_strategy': 'keystone',
'keystone_host': 'keystone_host',
'auth_port': '5000',
'auth_protocol': 'https',
'quantum_url': 'http://quantum_url',
'service_tenant_name': 'admin',
'service_username': 'admin',
'service_password': 'openstack',
'admin_domain_name': 'admin_domain',
'quantum_security_groups': 'yes',
'quantum_plugin': 'ovs',
'auth_host': 'keystone_host',
}
def fake_log(msg, level=None):
level = level or 'INFO'
print('[juju test log ({})] {}'.format(level, msg))
def raise_no_space(self):
raise context.NoNetworkBinding
class FakeUnitdata(object):
def __init__(self, **kwargs):
self.unit_data = {}
for name, value in kwargs.items():
self.unit_data[name] = value
def get(self, key, default=None, record=False):
return self.unit_data.get(key, default)
def set(self, key, value):
self.unit_data[key] = value
def flush(self):
pass
class LxdContextTests(CharmTestCase):
def setUp(self):
super(LxdContextTests, self).setUp(context, TO_PATCH)
self.relation_get.side_effect = self.test_relation.get
self.relation_ids.return_value = 'lxd:0'
self.related_units.return_value = 'lxd/0'
def test_with_pool(self):
self.test_relation.set({'pool': 'juju_lxd'})
lxd = context.LxdContext()()
self.assertEqual(lxd.get('storage_pool'), 'juju_lxd')
def test_without_pool(self):
lxd = context.LxdContext()()
self.assertEqual(lxd.get('storage_pool'), None)
class NovaComputeContextTests(CharmTestCase):
def setUp(self):
super(NovaComputeContextTests, self).setUp(context, TO_PATCH)
self.os_release.return_value = 'kilo'
self.relation_get.side_effect = self.test_relation.get
self.config.side_effect = self.test_config.get
self.log.side_effect = fake_log
self.host_uuid = 'e46e530d-18ae-4a67-9ff0-e6e2ba7c60a7'
self.maxDiff = None
def test_cloud_compute_context_no_relation(self):
self.relation_ids.return_value = []
cloud_compute = context.CloudComputeContext()
self.assertEqual({}, cloud_compute())
@patch.object(context, '_network_manager')
def test_cloud_compute_context_restart_trigger(self, nm):
nm.return_value = None
cloud_compute = context.CloudComputeContext()
with patch.object(cloud_compute, 'restart_trigger') as rt:
rt.return_value = 'footrigger'
ctxt = cloud_compute()
self.assertEqual(ctxt.get('restart_trigger'), 'footrigger')
with patch.object(cloud_compute, 'restart_trigger') as rt:
rt.return_value = None
ctxt = cloud_compute()
self.assertEqual(ctxt.get('restart_trigger'), None)
@patch.object(context, '_network_manager')
def test_cloud_compute_volume_context_cinder(self, netman):
netman.return_value = None
self.relation_ids.return_value = 'cloud-compute:0'
self.related_units.return_value = 'nova-cloud-controller/0'
cloud_compute = context.CloudComputeContext()
self.test_relation.set({'volume_service': 'cinder'})
self.assertEqual({'volume_service': 'cinder',
'cross_az_attach': True}, cloud_compute())
@patch.object(context, '_network_manager')
def test_cloud_compute_cross_az_context(self, netman):
netman.return_value = None
self.relation_ids.return_value = 'cloud-compute:1'
self.related_units.return_value = 'nova-cloud-controller/0'
cloud_compute = context.CloudComputeContext()
# Check no cross_az_attach value set, defaults to cross_az_attach=True
self.test_relation.set({'volume_service': 'cinder'})
self.assertEqual({'volume_service': 'cinder',
'cross_az_attach': True}, cloud_compute())
# Check that explicit True setting for cross_az_attach
self.test_relation.set({'volume_service': 'cinder',
'cross_az_attach': True})
self.assertEqual({'volume_service': 'cinder',
'cross_az_attach': True}, cloud_compute())
# Check false setting for cross_az_attach
self.test_relation.set({'volume_service': 'cinder',
'cross_az_attach': False})
self.assertEqual({'volume_service': 'cinder',
'cross_az_attach': False}, cloud_compute())
@patch.object(context, '_network_manager')
def test_cloud_compute_flatdhcp_context(self, netman):
netman.return_value = 'flatdhcpmanager'
self.relation_ids.return_value = 'cloud-compute:0'
self.related_units.return_value = 'nova-cloud-controller/0'
self.test_relation.set({
'network_manager': 'FlatDHCPManager',
'ec2_host': 'novaapihost'})
cloud_compute = context.CloudComputeContext()
ex_ctxt = {
'network_manager': 'flatdhcpmanager',
'network_manager_config': {
'ec2_dmz_host': 'novaapihost',
'flat_interface': 'eth1'
},
}
self.assertEqual(ex_ctxt, cloud_compute())
@patch.object(context, '_network_manager')
def test_cloud_compute_vendordata_context(self, netman):
self.relation_ids.return_value = 'cloud-compute:0'
self.related_units.return_value = 'nova-cloud-controller/0'
data = ('{"vendor_data": true, "vendor_data_url": "fake_url",'
' "foo": "bar",'
' "vendordata_providers": "StaticJSON,DynamicJSON"}')
self.test_relation.set({
'vendor_data': data
})
cloud_compute = context.CloudComputeContext()
ex_ctxt = {
'vendor_data': True,
'vendor_data_url': 'fake_url',
'vendordata_providers': 'StaticJSON,DynamicJSON',
}
self.assertEqual(ex_ctxt, cloud_compute())
def test_cloud_compute_vendorJSON_context(self):
self.relation_ids.return_value = 'cloud-compute:0'
self.related_units.return_value = 'nova-cloud-controller/0'
data = '{"good": json"}'
self.test_relation.set({
'vendor_json': data
})
cloud_compute = context.CloudComputeVendorJSONContext()
ex_ctxt = {'vendor_data_json': data}
self.assertEqual(ex_ctxt, cloud_compute())
def test_cloud_compute_vendorJSON_context_empty(self):
self.relation_ids.return_value = 'cloud-compute:0'
self.related_units.return_value = 'nova-cloud-controller/0'
data = ''
self.test_relation.set({
'vendor_json': data
})
cloud_compute = context.CloudComputeVendorJSONContext()
ex_ctxt = {'vendor_data_json': '{}'}
self.assertEqual(ex_ctxt, cloud_compute())
@patch.object(context, '_neutron_plugin')
@patch.object(context, '_neutron_url')
@patch.object(context, '_network_manager')
def test_cloud_compute_neutron_context(self, netman, url, plugin):
self.relation_ids.return_value = 'cloud-compute:0'
self.related_units.return_value = 'nova-cloud-controller/0'
netman.return_value = 'neutron'
plugin.return_value = 'ovs'
url.return_value = 'http://nova-c-c:9696'
self.test_relation.set(NEUTRON_CONTEXT)
cloud_compute = context.CloudComputeContext()
ex_ctxt = {
'network_manager': 'neutron',
'network_manager_config': {
'api_version': '2.0',
'admin_role': 'Admin',
'auth_protocol': 'https',
'service_protocol': 'http',
'auth_port': '5000',
'keystone_host': 'keystone_host',
'neutron_admin_auth_url': 'https://keystone_host:5000/v2.0',
'neutron_admin_password': 'openstack',
'neutron_admin_tenant_name': 'admin',
'neutron_admin_username': 'admin',
'neutron_admin_domain_name': 'admin_domain',
'neutron_auth_strategy': 'keystone',
'neutron_plugin': 'ovs',
'neutron_security_groups': True,
'neutron_url': 'http://nova-c-c:9696',
'service_protocol': 'http',
'service_port': '5000',
},
'service_host': 'keystone_host',
'admin_tenant_name': 'admin',
'admin_user': 'admin',
'admin_password': 'openstack',
'admin_role': 'Admin',
'admin_domain_name': 'admin_domain',
'auth_port': '5000',
'auth_protocol': 'https',
'auth_host': 'keystone_host',
'api_version': '2.0',
'service_protocol': 'http',
'service_port': '5000',
}
self.assertEqual(ex_ctxt, cloud_compute())
self._save_flag_file.assert_called_with(
path='/etc/nova/nm.conf', data='neutron')
@patch.object(context, '_neutron_plugin')
@patch.object(context, '_neutron_url')
@patch.object(context, '_network_manager')
def test_cloud_compute_neutron_ctxt_dns_domain(self, netman, url, plugin):
self.relation_ids.return_value = 'cloud-compute:0'
self.related_units.return_value = 'nova-cloud-controller/0'
netman.return_value = 'neutron'
plugin.return_value = 'ovs'
url.return_value = 'http://nova-c-c:9696'
neutron_context = NEUTRON_CONTEXT.copy()
neutron_context.update({'dns_domain': 'example.tld'})
self.test_relation.set(neutron_context)
cloud_compute = context.CloudComputeContext()
ex_ctxt = {
'network_manager': 'neutron',
'network_manager_config': {
'api_version': '2.0',
'admin_role': 'Admin',
'auth_protocol': 'https',
'service_protocol': 'http',
'auth_port': '5000',
'dns_domain': 'example.tld',
'keystone_host': 'keystone_host',
'neutron_admin_auth_url': 'https://keystone_host:5000/v2.0',
'neutron_admin_password': 'openstack',
'neutron_admin_tenant_name': 'admin',
'neutron_admin_username': 'admin',
'neutron_admin_domain_name': 'admin_domain',
'neutron_auth_strategy': 'keystone',
'neutron_plugin': 'ovs',
'neutron_security_groups': True,
'neutron_url': 'http://nova-c-c:9696',
'service_protocol': 'http',
'service_port': '5000',
},
'service_host': 'keystone_host',
'admin_tenant_name': 'admin',
'admin_user': 'admin',
'admin_password': 'openstack',
'admin_role': 'Admin',
'admin_domain_name': 'admin_domain',
'auth_port': '5000',
'auth_protocol': 'https',
'auth_host': 'keystone_host',
'api_version': '2.0',
'dns_domain': 'example.tld',
'service_protocol': 'http',
'service_port': '5000',
}
self.assertEqual(ex_ctxt, cloud_compute())
self._save_flag_file.assert_called_with(
path='/etc/nova/nm.conf', data='neutron')
@patch.object(context, '_neutron_plugin')
@patch.object(context, '_neutron_url')
@patch.object(context, '_network_manager')
def test_cloud_compute_neutron_ctxt_physnets(self, netman, url, plugin):
self.relation_ids.return_value = 'cloud-compute:0'
self.related_units.return_value = 'nova-cloud-controller/0'
self.test_config.set('neutron-physnets', 'foo:0;bar:0,1')
self.test_config.set('neutron-tunnel', '0,1')
netman.return_value = 'neutron'
plugin.return_value = 'ovs'
url.return_value = 'http://nova-c-c:9696'
self.test_relation.set(NEUTRON_CONTEXT)
cloud_compute = context.CloudComputeContext()
ex_ctxt = {
'api_version': '2.0',
'admin_role': 'Admin',
'auth_protocol': 'https',
'service_protocol': 'http',
'auth_port': '5000',
'keystone_host': 'keystone_host',
'neutron_admin_auth_url': 'https://keystone_host:5000/v2.0',
'neutron_admin_password': 'openstack',
'neutron_admin_tenant_name': 'admin',
'neutron_admin_username': 'admin',
'neutron_admin_domain_name': 'admin_domain',
'neutron_auth_strategy': 'keystone',
'neutron_physnets': {'bar': '0,1', 'foo': '0'},
'neutron_tunnel': '0,1',
'neutron_plugin': 'ovs',
'neutron_security_groups': True,
'neutron_url': 'http://nova-c-c:9696',
'service_protocol': 'http',
'service_port': '5000',
}
self.assertEqual(ex_ctxt, cloud_compute()['network_manager_config'])
@patch.object(context, '_network_manager')
@patch.object(context, '_neutron_plugin')
def test_neutron_plugin_context_no_setting(self, plugin, nm):
plugin.return_value = None
nm.return_Value = None
qplugin = context.NeutronComputeContext()
self.assertEqual({}, qplugin())
def test_libvirt_context_libvirtd(self):
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'yakkety'}
self.os_release.return_value = 'ocata'
self.kv.return_value = FakeUnitdata(**{'host_uuid': self.host_uuid})
self.test_config.set('enable-live-migration', False)
libvirt = context.NovaComputeLibvirtContext()
self.assertEqual(
{'libvirtd_opts': '',
'libvirt_user': 'libvirt',
'arch': platform.machine(),
'ksm': 'AUTO',
'kvm_hugepages': 0,
'listen_tls': 0,
'host_uuid': self.host_uuid,
'force_raw_images': True,
'inject_password': False,
'inject_partition': -2,
'block_device_allocate_retries': 300,
'default_ephemeral_format': 'ext4',
'reserved_host_disk': 0,
'reserved_host_memory': 512}, libvirt())
@patch.object(context.subprocess, 'check_call')
def test_ensure_rbd_cleanup_rbd(self, call_mock):
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'focal'}
self.os_release.return_value = 'ussuri'
self.test_config.set('libvirt-image-backend', 'rbd')
libvirt = context.NovaComputeLibvirtContext()
result = libvirt()
self.assertIn('ensure_libvirt_rbd_instance_dir_cleanup', result)
self.assertTrue(result['ensure_libvirt_rbd_instance_dir_cleanup'])
call_mock.assert_called_once_with(
['df', '-l', '/var/lib/nova/instances'])
@patch.object(context.subprocess, 'check_call')
def test_ensure_rbd_cleanup_rbd_non_local_mount(self, call_mock):
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'focal'}
self.os_release.return_value = 'ussuri'
call_mock.side_effect = [context.subprocess.CalledProcessError(
1, 'df -l /var/foo/bar')]
self.test_config.set('libvirt-image-backend', 'rbd')
self.test_config.set('instances-path', '/var/foo/bar')
libvirt = context.NovaComputeLibvirtContext()
self.assertNotIn('ensure_libvirt_rbd_instance_dir_cleanup', libvirt())
call_mock.assert_called_once_with(['df', '-l', '/var/foo/bar'])
def test_ensure_rbd_cleanup_non_rbd(self):
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'focal'}
self.os_release.return_value = 'ussuri'
libvirt = context.NovaComputeLibvirtContext()
self.assertNotIn('ensure_libvirt_rbd_instance_dir_cleanup', libvirt())
def test_libvirt_context_inject_password(self):
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'zesty'}
self.os_release.return_value = 'ocata'
self.kv.return_value = FakeUnitdata(**{'host_uuid': self.host_uuid})
self.test_config.set('inject-password', True)
libvirt = context.NovaComputeLibvirtContext()
self.assertEqual(
{'libvirtd_opts': '',
'libvirt_user': 'libvirt',
'arch': platform.machine(),
'ksm': 'AUTO',
'kvm_hugepages': 0,
'listen_tls': 0,
'host_uuid': self.host_uuid,
'force_raw_images': True,
'inject_password': True,
'inject_partition': -1,
'block_device_allocate_retries': 300,
'default_ephemeral_format': 'ext4',
'reserved_host_disk': 0,
'reserved_host_memory': 512}, libvirt())
def test_libvirt_context_block_device_allocate_retries(self):
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'focal'}
self.os_release.return_value = 'ussuri'
self.kv.return_value = FakeUnitdata(**{'host_uuid': self.host_uuid})
self.test_config.set('block-device-allocate-retries', 120)
self.test_config.set('block-device-allocate-retries-interval', 5)
libvirt = context.NovaComputeLibvirtContext()
self.assertEqual(
{'libvirtd_opts': '',
'libvirt_user': 'libvirt',
'arch': platform.machine(),
'ksm': 'AUTO',
'kvm_hugepages': 0,
'listen_tls': 0,
'host_uuid': self.host_uuid,
'force_raw_images': True,
'inject_password': False,
'inject_partition': -2,
'block_device_allocate_retries': 120,
'block_device_allocate_retries_interval': 5,
'default_ephemeral_format': 'ext4',
'reserved_host_disk': 0,
'reserved_host_memory': 512}, libvirt())
def test_libvirt_context_libvirtd_reserved_huge_pages_1(self):
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'yakkety'}
self.os_release.return_value = 'ocata'
self.kv.return_value = FakeUnitdata(**{'host_uuid': self.host_uuid})
self.test_config.set('reserved-huge-pages', 'node:0,size:2048,count:6')
libvirt = context.NovaComputeLibvirtContext()
self.assertEqual(
{'libvirtd_opts': '',
'libvirt_user': 'libvirt',
'arch': platform.machine(),
'ksm': 'AUTO',
'kvm_hugepages': 0,
'listen_tls': 0,
'host_uuid': self.host_uuid,
'force_raw_images': True,
'inject_password': False,
'inject_partition': -2,
'block_device_allocate_retries': 300,
'default_ephemeral_format': 'ext4',
'reserved_host_disk': 0,
'reserved_host_memory': 512,
'reserved_huge_pages': ['node:0,size:2048,count:6']}, libvirt())
def test_libvirt_context_libvirtd_reserved_huge_pages_2(self):
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'yakkety'}
self.os_release.return_value = 'ocata'
self.kv.return_value = FakeUnitdata(**{'host_uuid': self.host_uuid})
self.test_config.set(
'reserved-huge-pages',
'node:0,size:2048,count:6;node:1,size:1G,count:32')
libvirt = context.NovaComputeLibvirtContext()
self.assertEqual(
{'libvirtd_opts': '',
'libvirt_user': 'libvirt',
'arch': platform.machine(),
'ksm': 'AUTO',
'kvm_hugepages': 0,
'listen_tls': 0,
'host_uuid': self.host_uuid,
'force_raw_images': True,
'inject_password': False,
'inject_partition': -2,
'block_device_allocate_retries': 300,
'default_ephemeral_format': 'ext4',
'reserved_host_disk': 0,
'reserved_host_memory': 512,
'reserved_huge_pages': ['node:0,size:2048,count:6',
'node:1,size:1G,count:32']}, libvirt())
def test_libvirt_bin_context_no_migration(self):
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'lucid'}
self.kv.return_value = FakeUnitdata(**{'host_uuid': self.host_uuid})
self.test_config.set('enable-live-migration', False)
libvirt = context.NovaComputeLibvirtContext()
self.assertEqual(
{'libvirtd_opts': '-d',
'libvirt_user': 'libvirtd',
'arch': platform.machine(),
'ksm': 'AUTO',
'kvm_hugepages': 0,
'listen_tls': 0,
'host_uuid': self.host_uuid,
'force_raw_images': True,
'inject_password': False,
'inject_partition': -2,
'block_device_allocate_retries': 300,
'default_ephemeral_format': 'ext4',
'reserved_host_disk': 0,
'reserved_host_memory': 512}, libvirt())
def test_libvirt_bin_context_migration_tcp_listen(self):
self.kv.return_value = FakeUnitdata(**{'host_uuid': self.host_uuid})
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'lucid'}
self.test_config.set('enable-live-migration', True)
libvirt = context.NovaComputeLibvirtContext()
self.assertEqual(
{'libvirtd_opts': '-d -l',
'libvirt_user': 'libvirtd',
'arch': platform.machine(),
'ksm': 'AUTO',
'kvm_hugepages': 0,
'listen_tls': 0,
'host_uuid': self.host_uuid,
'live_migration_uri': 'qemu+ssh://%s/system',
'live_migration_completion_timeout': 800,
'live_migration_downtime': 500,
'live_migration_downtime_delay': 75,
'live_migration_downtime_steps': 10,
'live_migration_permit_auto_converge': False,
'live_migration_permit_post_copy': False,
'default_ephemeral_format': 'ext4',
'force_raw_images': True,
'inject_password': False,
'inject_partition': -2,
'block_device_allocate_retries': 300,
'reserved_host_disk': 0,
'reserved_host_memory': 512}, libvirt())
def test_libvirt_context_without_migration_network(self):
self.kv.return_value = FakeUnitdata(**{'host_uuid': self.host_uuid})
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'xenial'}
self.test_config.set('enable-live-migration', True)
self.test_config.set('migration-auth-type', 'ssh')
self.os_release.return_value = 'kilo'
self.assertEqual(context.NovaComputeLibvirtContext()()[
'live_migration_uri'], 'qemu+ssh://%s/system')
def test_libvirt_context_with_migration_network(self):
self.kv.return_value = FakeUnitdata(**{'host_uuid': self.host_uuid})
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'xenial'}
self.test_config.set('enable-live-migration', True)
self.test_config.set('migration-auth-type', 'ssh')
self.test_config.set('libvirt-migration-network', '10.5.0.0/16')
self.os_release.return_value = 'rocky'
context.NovaComputeLibvirtContext()()
self.get_relation_ip.assert_called_with('migration',
cidr_network="10.5.0.0/16")
def test_libvirt_context_with_migration_space(self):
self.kv.return_value = FakeUnitdata(**{'host_uuid': self.host_uuid})
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'xenial'}
self.test_config.set('enable-live-migration', True)
self.os_release.return_value = 'ocata'
self.get_relation_ip.return_value = "10.5.0.5"
libvirt_context = context.NovaComputeLibvirtContext()()
self.get_relation_ip.assert_called_with('migration',
cidr_network=None)
self.assertTrue('live_migration_uri' not in libvirt_context.keys())
self.assertEqual(libvirt_context['live_migration_scheme'], 'ssh')
self.assertEqual(libvirt_context['live_migration_inbound_addr'],
'10.5.0.5')
def test_libvirt_bin_context_migration_tcp_listen_with_auto_converge(self):
self.kv.return_value = FakeUnitdata(**{'host_uuid': self.host_uuid})
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'lucid'}
self.test_config.set('enable-live-migration', True)
self.test_config.set('live-migration-permit-auto-converge', True)
libvirt = context.NovaComputeLibvirtContext()
self.assertEqual(
{'libvirtd_opts': '-d -l',
'libvirt_user': 'libvirtd',
'arch': platform.machine(),
'ksm': 'AUTO',
'kvm_hugepages': 0,
'listen_tls': 0,
'host_uuid': self.host_uuid,
'live_migration_uri': 'qemu+ssh://%s/system',
'live_migration_completion_timeout': 800,
'live_migration_downtime': 500,
'live_migration_downtime_delay': 75,
'live_migration_downtime_steps': 10,
'live_migration_permit_auto_converge': True,
'live_migration_permit_post_copy': False,
'force_raw_images': True,
'inject_password': False,
'inject_partition': -2,
'block_device_allocate_retries': 300,
'default_ephemeral_format': 'ext4',
'reserved_host_disk': 0,
'reserved_host_memory': 512}, libvirt())
def test_libvirt_bin_context_migration_tcp_listen_with_post_copy(self):
self.kv.return_value = FakeUnitdata(**{'host_uuid': self.host_uuid})
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'lucid'}
self.test_config.set('enable-live-migration', True)
self.test_config.set('live-migration-permit-post-copy', True)
libvirt = context.NovaComputeLibvirtContext()
self.assertEqual(
{'libvirtd_opts': '-d -l',
'libvirt_user': 'libvirtd',
'arch': platform.machine(),
'ksm': 'AUTO',
'kvm_hugepages': 0,
'listen_tls': 0,
'host_uuid': self.host_uuid,
'live_migration_uri': 'qemu+ssh://%s/system',
'live_migration_completion_timeout': 800,
'live_migration_downtime': 500,
'live_migration_downtime_delay': 75,
'live_migration_downtime_steps': 10,
'live_migration_permit_auto_converge': False,
'live_migration_permit_post_copy': True,
'default_ephemeral_format': 'ext4',
'force_raw_images': True,
'inject_password': False,
'inject_partition': -2,
'block_device_allocate_retries': 300,
'reserved_host_disk': 0,
'reserved_host_memory': 512}, libvirt())
def test_libvirt_disk_cachemodes(self):
self.kv.return_value = FakeUnitdata(**{'host_uuid': self.host_uuid})
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'lucid'}
self.test_config.set('disk-cachemodes', 'file=unsafe,block=none')
libvirt = context.NovaComputeLibvirtContext()
self.assertEqual(
{'libvirtd_opts': '-d',
'libvirt_user': 'libvirtd',
'disk_cachemodes': 'file=unsafe,block=none',
'arch': platform.machine(),
'ksm': 'AUTO',
'kvm_hugepages': 0,
'listen_tls': 0,
'host_uuid': self.host_uuid,
'force_raw_images': True,
'inject_password': False,
'inject_partition': -2,
'block_device_allocate_retries': 300,
'default_ephemeral_format': 'ext4',
'reserved_host_disk': 0,
'reserved_host_memory': 512}, libvirt())
def test_libvirt_hugepages(self):
self.kv.return_value = FakeUnitdata(**{'host_uuid': self.host_uuid})
self.os_release.return_value = 'kilo'
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'lucid'}
self.test_config.set('hugepages', '22')
libvirt = context.NovaComputeLibvirtContext()
self.assertEqual(
{'libvirtd_opts': '-d',
'libvirt_user': 'libvirtd',
'arch': platform.machine(),
'hugepages': True,
'ksm': 'AUTO',
'kvm_hugepages': 1,
'listen_tls': 0,
'host_uuid': self.host_uuid,
'force_raw_images': True,
'inject_password': False,
'inject_partition': -2,
'block_device_allocate_retries': 300,
'default_ephemeral_format': 'ext4',
'reserved_host_disk': 0,
'reserved_host_memory': 512}, libvirt())
def test_libvirt_context_libvirtd_force_raw_images(self):
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'zesty'}
self.os_release.return_value = 'ocata'
self.kv.return_value = FakeUnitdata(**{'host_uuid': self.host_uuid})
self.test_config.set('force-raw-images', False)
libvirt = context.NovaComputeLibvirtContext()
self.assertEqual(
{'libvirtd_opts': '',
'libvirt_user': 'libvirt',
'arch': platform.machine(),
'ksm': 'AUTO',
'kvm_hugepages': 0,
'listen_tls': 0,
'host_uuid': self.host_uuid,
'force_raw_images': False,
'inject_password': False,
'inject_partition': -2,
'block_device_allocate_retries': 300,
'default_ephemeral_format': 'ext4',
'reserved_host_disk': 0,
'reserved_host_memory': 512}, libvirt())
def test_lxd_live_migration_opts_xenial(self):
self.kv.return_value = FakeUnitdata(**{'host_uuid': self.host_uuid})
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'xenial'}
self.test_config.set('enable-live-migration', False)
self.test_config.set('virt-type', 'lxd')
lxd = context.NovaComputeVirtContext()
self.assertEqual(
{'resume_guests_state_on_host_boot': False,
'allow_resize_to_same_host': False}, lxd())
def test_lxd_live_migration_opts_yakkety(self):
self.kv.return_value = FakeUnitdata(**{'host_uuid': self.host_uuid})
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'yakkety'}
self.test_config.set('enable-live-migration', True)
self.test_config.set('virt-type', 'lxd')
lxd = context.NovaComputeVirtContext()
self.assertEqual(
{'enable_live_migration': True,
'resume_guests_state_on_host_boot': False,
'allow_resize_to_same_host': False,
'virt_type': 'lxd'}, lxd())
def test_resume_guests_state_on_host_boot(self):
self.kv.return_value = FakeUnitdata(**{'host_uuid': self.host_uuid})
self.os_release.return_value = 'diablo'
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'lucid'}
self.test_config.set('resume-guests-state-on-host-boot', True)
lxd = context.NovaComputeVirtContext()
self.assertEqual(
{'resume_guests_state_on_host_boot': True,
'allow_resize_to_same_host': False}, lxd())
def test_allow_resize_to_same_host_empty(self):
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'lucid'}
self.relation_ids.return_value = ['cloud-compute:0']
self.related_units.return_value = 'nova-cloud-controller/0'
self.test_relation.set({
'allow_resize_to_same_host': None,
})
self.assertEqual(
{'resume_guests_state_on_host_boot': False,
'allow_resize_to_same_host': False},
context.NovaComputeVirtContext()())
def test_allow_resize_to_same_host_enabled(self):
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'lucid'}
self.relation_ids.return_value = ['cloud-compute:0']
self.related_units.return_value = 'nova-cloud-controller/0'
self.test_relation.set({
'allow_resize_to_same_host': 'true',
})
self.assertEqual(
{'resume_guests_state_on_host_boot': False,
'allow_resize_to_same_host': True},
context.NovaComputeVirtContext()())
def test_allow_resize_to_same_host_disabled(self):
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'lucid'}
self.relation_ids.return_value = ['cloud-compute:0']
self.related_units.return_value = 'nova-cloud-controller/0'
self.test_relation.set({
'allow_resize_to_same_host': 'false',
})
self.assertEqual(
{'resume_guests_state_on_host_boot': False,
'allow_resize_to_same_host': False},
context.NovaComputeVirtContext()())
@patch.object(context.uuid, 'uuid4')
def test_libvirt_new_uuid(self, mock_uuid):
self.kv.return_value = FakeUnitdata()
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'lucid'}
mock_uuid.return_value = '73874c1c-ba48-406d-8d99-ac185d83b9bc'
libvirt = context.NovaComputeLibvirtContext()
self.assertEqual(libvirt()['host_uuid'],
'73874c1c-ba48-406d-8d99-ac185d83b9bc')
def test_libvirt_opts_trusty(self):
self.kv.return_value = FakeUnitdata(**{'host_uuid': self.host_uuid})
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'trusty'}
libvirt = context.NovaComputeLibvirtContext()
self.assertEqual(libvirt()['libvirtd_opts'], '-d')
def test_libvirt_opts_xenial(self):
self.kv.return_value = FakeUnitdata(**{'host_uuid': self.host_uuid})
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'xenial'}
libvirt = context.NovaComputeLibvirtContext()
self.assertEqual(libvirt()['libvirtd_opts'], '')
@patch.object(context.uuid, 'uuid4')
def test_libvirt_cpu_mode_host_passthrough(self, mock_uuid):
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'lucid'}
self.test_config.set('cpu-mode', 'host-passthrough')
mock_uuid.return_value = 'e46e530d-18ae-4a67-9ff0-e6e2ba7c60a7'
libvirt = context.NovaComputeLibvirtContext()
self.assertEqual(libvirt()['cpu_mode'],
'host-passthrough')
@patch.object(context.uuid, 'uuid4')
def test_libvirt_cpu_mode_none(self, mock_uuid):
self.test_config.set('cpu-mode', 'none')
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'lucid'}
mock_uuid.return_value = 'e46e530d-18ae-4a67-9ff0-e6e2ba7c60a7'
libvirt = context.NovaComputeLibvirtContext()
self.assertEqual(libvirt()['cpu_mode'],
'none')
@patch.object(context.uuid, 'uuid4')
def test_libvirt_cpu_mode_custom_model(self, mock_uuid):
self.test_config.set('cpu-mode', 'custom')
self.test_config.set('cpu-model', 'Broadwell')
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'bionic'}
mock_uuid.return_value = 'e46e530d-18ae-4a67-9ff0-e6e2ba7c60a7'
libvirt = context.NovaComputeLibvirtContext()
self.assertEqual(libvirt()['cpu_mode'], 'custom')
self.assertEqual(libvirt()['cpu_model'], 'Broadwell')
# should be ignored
self.test_config.set('cpu-mode', 'host-model')
self.test_config.set('cpu-model', 'Haswell')
libvirt = context.NovaComputeLibvirtContext()
self.assertNotIn('cpu-model', libvirt())
@patch.object(context.uuid, 'uuid4')
def test_libvirt_cpu_mode_custom_models(self, mock_uuid):
self.test_config.set('cpu-mode', 'custom')
self.test_config.set('cpu-models',
'SandyBridge,IvyBridge,Haswell,Broadwell')
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'bionic'}
mock_uuid.return_value = 'e46e530d-18ae-4a67-9ff0-e6e2ba7c60a7'
libvirt = context.NovaComputeLibvirtContext()
self.assertEqual(libvirt()['cpu_mode'], 'custom')
self.assertEqual(libvirt()['cpu_models'],
'SandyBridge,IvyBridge,Haswell,Broadwell')
# should be ignored
self.test_config.set('cpu-model', 'Haswell')
libvirt = context.NovaComputeLibvirtContext()
self.assertNotIn('cpu_model', libvirt())
@patch.object(context, 'platform')
@patch.object(context.uuid, 'uuid4')
def test_libvirt_cpu_mode_aarch64(self, mock_uuid, mock_platform):
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'xenial'}
mock_uuid.return_value = 'e46e530d-18ae-4a67-9ff0-e6e2ba7c60a7'
mock_platform.machine.return_value = 'aarch64'
libvirt = context.NovaComputeLibvirtContext()
self.assertEqual(libvirt()['cpu_mode'],
'host-passthrough')
def test_libvirt_vnf_configs(self):
self.kv.return_value = FakeUnitdata(**{'host_uuid': self.host_uuid})
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'lucid'}
self.test_config.set('hugepages', '22')
self.test_config.set('reserved-host-memory', 1024)
self.test_config.set('reserved-host-disk', 65536)
self.test_config.set('vcpu-pin-set', '^0^2')
self.test_config.set('pci-passthrough-whitelist', 'mypcidevices')
self.test_config.set('virtio-net-tx-queue-size', 512)
self.test_config.set('virtio-net-rx-queue-size', 1024)
self.test_config.set('num-pcie-ports', 15)
self.test_config.set('cpu-shared-set', "4-12,^8,15")
self.test_config.set('cpu-dedicated-set', "0-3,^10,33")
libvirt = context.NovaComputeLibvirtContext()
self.assertEqual(
{'libvirtd_opts': '-d',
'libvirt_user': 'libvirtd',
'arch': platform.machine(),
'ksm': 'AUTO',
'hugepages': True,
'kvm_hugepages': 1,
'listen_tls': 0,
'host_uuid': self.host_uuid,
'reserved_host_memory': 1024,
'reserved_host_disk': 65536,
'force_raw_images': True,
'inject_password': False,
'inject_partition': -2,
'block_device_allocate_retries': 300,
'pci_passthrough_whitelist': 'mypcidevices',
'virtio_net_tx_queue_size': 512,
'virtio_net_rx_queue_size': 1024,
'num_pcie_ports': 15,
'default_ephemeral_format': 'ext4',
'cpu_shared_set': "4-12,^8,15",
'cpu_dedicated_set': "0-3,^10,33"}, libvirt())
def test_vcpu_pin_set(self):
self.kv.return_value = FakeUnitdata(**{'host_uuid': self.host_uuid})
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'lucid'}
self.test_config.set('vcpu-pin-set', '^0^2')
libvirt = context.NovaComputeLibvirtContext()
self.assertEqual(
{'libvirtd_opts': '-d',
'libvirt_user': 'libvirtd',
'arch': platform.machine(),
'ksm': 'AUTO',
'kvm_hugepages': 0,
'listen_tls': 0,
'host_uuid': self.host_uuid,
'reserved_host_disk': 0,
'reserved_host_memory': 512,
'vcpu_pin_set': '^0^2',
'force_raw_images': True,
'inject_password': False,
'inject_partition': -2,
'block_device_allocate_retries': 300,
'default_ephemeral_format': 'ext4'}, libvirt())
def test_cpu_dedicated_set(self):
self.kv.return_value = FakeUnitdata(**{'host_uuid': self.host_uuid})
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'lucid'}
self.test_config.set('cpu-shared-set', '4-15')
self.test_config.set('cpu-dedicated-set', '16-31')
libvirt = context.NovaComputeLibvirtContext()
expected = {'libvirtd_opts': '-d',
'libvirt_user': 'libvirtd',
'arch': platform.machine(),
'ksm': 'AUTO',
'kvm_hugepages': 0,
'listen_tls': 0,
'host_uuid': self.host_uuid,
'reserved_host_disk': 0,
'reserved_host_memory': 512,
'cpu_shared_set': '4-15',
'cpu_dedicated_set': '16-31',
'force_raw_images': True,
'inject_password': False,
'inject_partition': -2,
'block_device_allocate_retries': 300,
'default_ephemeral_format': 'ext4'}
self.assertEqual(expected, libvirt())
# should be ignored
self.test_config.set('vcpu-pin-set', '16-31')
libvirt = context.NovaComputeLibvirtContext()
self.assertEqual(expected, libvirt())
def test_ksm_configs(self):
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'lucid'}
self.test_config.set('ksm', '1')
libvirt = context.NovaComputeLibvirtContext()
self.assertTrue(libvirt()['ksm'] == '1')
self.test_config.set('ksm', '0')
libvirt = context.NovaComputeLibvirtContext()
self.assertTrue(libvirt()['ksm'] == '0')
self.test_config.set('ksm', 'AUTO')
libvirt = context.NovaComputeLibvirtContext()
self.assertTrue(libvirt()['ksm'] == 'AUTO')
self.test_config.set('ksm', '')
libvirt = context.NovaComputeLibvirtContext()
self.assertTrue(libvirt()['ksm'] == 'AUTO')
self.os_release.return_value = 'ocata'
self.test_config.set('ksm', 'AUTO')
libvirt = context.NovaComputeLibvirtContext()
self.assertTrue(libvirt()['ksm'] == 'AUTO')
self.os_release.return_value = 'kilo'
self.test_config.set('ksm', 'AUTO')
libvirt = context.NovaComputeLibvirtContext()
self.assertTrue(libvirt()['ksm'] == 'AUTO')
self.os_release.return_value = 'diablo'
self.test_config.set('ksm', 'AUTO')
libvirt = context.NovaComputeLibvirtContext()
self.assertTrue(libvirt()['ksm'] == '1')
@patch.object(context.uuid, 'uuid4')
def test_libvirt_cpu_mode_default(self, mock_uuid):
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'lucid'}
libvirt = context.NovaComputeLibvirtContext()
self.assertFalse('cpu-mode' in libvirt())
@patch('subprocess.call')
def test_host_IP_context(self, _call):
self.log = fake_log
self.get_relation_ip.return_value = '172.24.0.79'
host_ip = context.HostIPContext()
self.assertEqual({'host_ip': '172.24.0.79'}, host_ip())
self.get_relation_ip.assert_called_with('cloud-compute',
cidr_network=None)
@patch('subprocess.call')
def test_host_IP_context_ipv6(self, _call):
self.log = fake_log
self.test_config.set('prefer-ipv6', True)
self.get_relation_ip.return_value = '2001:db8:0:1::2'
self.kv.return_value = FakeUnitdata()
host_ip = context.HostIPContext()
self.assertEqual({'host_ip': '2001:db8:0:1::2'}, host_ip())
self.assertTrue(self.get_relation_ip.called)
def test_metadata_service_ctxt(self):
self.relation_ids.return_value = 'neutron-plugin:0'
self.related_units.return_value = 'neutron-openvswitch/0'
self.test_relation.set({'metadata-shared-secret': 'shared_secret'})
metadatactxt = context.MetadataServiceContext()
self.assertEqual(metadatactxt(), {'metadata_shared_secret':
'shared_secret'})
def test_nova_metadata_requirement(self):
self.relation_ids.return_value = ['neutron-plugin:0']
self.related_units.return_value = ['neutron-api/0']
self.test_relation.set({'metadata-shared-secret': 'secret'})
self.assertEqual(context.nova_metadata_requirement(),
(True, 'secret'))
self.test_relation.set({})
self.assertEqual(context.nova_metadata_requirement(),
(False, None))
self.test_relation.set({'enable-metadata': 'true'})
self.assertEqual(context.nova_metadata_requirement(),
(True, None))
@patch('nova_compute_context.local_unit')
def test_sent_ceph_application_name_empty_rel_data_default(
self, local_unit):
local_unit.return_value = 'nova-compute-kvm/0'
self.relation_ids.return_value = ['ceph:0']
self.test_relation.set({})
self.service_name.return_value = 'nova-compute-kvm'
self.assertEqual(
context.sent_ceph_application_name(), 'nova-compute-kvm')
@patch('nova_compute_context.local_unit')
def test_sent_ceph_application_name(self, local_unit):
local_unit.return_value = 'nova-compute-kvm/0'
self.relation_ids.return_value = ['ceph:0']
self.test_relation.set({'application-name': 'ceph-nova-compute'})
self.service_name.return_value = 'nova-compute-kvm'
self.assertEqual(
context.sent_ceph_application_name(), 'ceph-nova-compute')
def test_nova_compute_extra_flags(self):
self.test_config.set('cpu-model-extra-flags', 'pcid vmx pdpe1gb')
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'bionic'}
libvirt = context.NovaComputeLibvirtContext()
self.assertEqual(libvirt()['cpu_model_extra_flags'],
'pcid, vmx, pdpe1gb')
_pci_alias1 = (
'{'
'"name": "IntelNIC",'
'"capability_type": "pci",'
'"product_id": "1111",'
'"vendor_id": "8086",'
'"device_type": "type-PF"'
'}'
)
_pci_alias2 = (
'{'
'"name": " Cirrus Logic ",'
'"capability_type": "pci",'
'"product_id": "0ff2",'
'"vendor_id": "10de",'
'"device_type": "type-PCI"'
'}'
)
_pci_alias_list = "[" + _pci_alias1 + "," + _pci_alias2 + "]"
@patch('charmhelpers.contrib.openstack.ip.unit_get')
@patch('charmhelpers.contrib.hahelpers.cluster.relation_ids')
@patch('charmhelpers.core.hookenv.local_unit')
@patch('charmhelpers.contrib.openstack.context.config')
def test_nova_config_context_multi_pci_alias_pike(self, mock_config,
local_unit,
mock_relation_ids,
mock_unit_get):
self.os_release.return_value = 'pike'
local_unit.return_value = 'nova-compute/0'
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'xenial'}
mock_config.side_effect = self.test_config.get
mock_unit_get.return_value = '127.0.0.1'
self.test_config.set('pci-alias', self._pci_alias_list)
ctxt = context.NovaComputeLibvirtContext()()
self.assertEqual(
ctxt['pci_alias'],
('[{"capability_type": "pci", "device_type": "type-PF", '
'"name": "IntelNIC", "product_id": "1111", '
'"vendor_id": "8086"}, '
'{"capability_type": "pci", "device_type": "type-PCI", '
'"name": " Cirrus Logic ", "product_id": "0ff2", '
'"vendor_id": "10de"}]'))
@patch('charmhelpers.contrib.openstack.ip.unit_get')
@patch('charmhelpers.contrib.hahelpers.cluster.relation_ids')
@patch('charmhelpers.core.hookenv.local_unit')
@patch('charmhelpers.contrib.openstack.context.config')
def test_nova_config_context_multi_pci_alias(self, mock_config,
local_unit,
mock_relation_ids,
mock_unit_get):
local_unit.return_value = 'nova-compute/0'
self.os_release.return_value = 'queens'
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'bionic'}
mock_config.side_effect = self.test_config.get
mock_unit_get.return_value = '127.0.0.1'
self.test_config.set('pci-alias', self._pci_alias1)
ctxt = context.NovaComputeLibvirtContext()()
self.assertEqual(
ctxt['pci_alias'],
('{"capability_type": "pci", "device_type": "type-PF", '
'"name": "IntelNIC", "product_id": "1111", '
'"vendor_id": "8086"}'))
@patch('charmhelpers.contrib.openstack.ip.unit_get')
@patch('charmhelpers.contrib.hahelpers.cluster.relation_ids')
@patch('charmhelpers.core.hookenv.local_unit')
@patch('charmhelpers.contrib.openstack.context.config')
def test_nova_config_context_multi_pci_aliases(self, mock_config,
local_unit,
mock_relation_ids,
mock_unit_get):
local_unit.return_value = 'nova-compute/0'
self.os_release.return_value = 'queens'
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'bionic'}
mock_config.side_effect = self.test_config.get
mock_unit_get.return_value = '127.0.0.1'
self.test_config.set('pci-alias', self._pci_alias_list)
ctxt = context.NovaComputeLibvirtContext()()
self.assertEqual(
ctxt['pci_aliases'][0],
('{"capability_type": "pci", "device_type": "type-PF", '
'"name": "IntelNIC", "product_id": "1111", '
'"vendor_id": "8086"}'))
self.assertEqual(
ctxt['pci_aliases'][1],
('{"capability_type": "pci", "device_type": "type-PCI", '
'"name": " Cirrus Logic ", "product_id": "0ff2", '
'"vendor_id": "10de"}'))
@patch.object(context.os.environ, 'get')
def test_get_az_customize_with_env(self, os_environ_get_mock):
self.test_config.set('customize-failure-domain', True)
self.test_config.set('default-availability-zone', 'nova')
def os_environ_get_side_effect(key):
return {
'JUJU_AVAILABILITY_ZONE': 'az1',
}[key]
os_environ_get_mock.side_effect = os_environ_get_side_effect
az = context.get_availability_zone()
self.assertEqual('az1', az)
@patch.object(context.os.environ, 'get')
def test_get_az_customize_without_env(self, os_environ_get_mock):
self.test_config.set('customize-failure-domain', True)
self.test_config.set('default-availability-zone', 'mynova')
def os_environ_get_side_effect(key):
return {
'JUJU_AVAILABILITY_ZONE': '',
}[key]
os_environ_get_mock.side_effect = os_environ_get_side_effect
az = context.get_availability_zone()
self.assertEqual('mynova', az)
@patch.object(context.os.environ, 'get')
def test_get_az_no_customize_without_env(self, os_environ_get_mock):
self.test_config.set('customize-failure-domain', False)
self.test_config.set('default-availability-zone', 'nova')
def os_environ_get_side_effect(key):
return {
'JUJU_AVAILABILITY_ZONE': '',
}[key]
os_environ_get_mock.side_effect = os_environ_get_side_effect
az = context.get_availability_zone()
self.assertEqual('nova', az)
@patch.object(context.os.environ, 'get')
def test_get_az_no_customize_with_env(self, os_environ_get_mock):
self.test_config.set('customize-failure-domain', False)
self.test_config.set('default-availability-zone', 'nova')
def os_environ_get_side_effect(key):
return {
'JUJU_AVAILABILITY_ZONE': 'az1',
}[key]
os_environ_get_mock.side_effect = os_environ_get_side_effect
az = context.get_availability_zone()
self.assertEqual('nova', az)
class IronicAPIContextTests(CharmTestCase):
def setUp(self):
super(IronicAPIContextTests, self).setUp(context, TO_PATCH)
self.relation_get.side_effect = self.test_relation.get
def test_ironic_api_ready_no_relation(self):
self.relation_ids.return_value = []
self.assertEqual(
context.IronicAPIContext()(), {})
def test_ironic_api_ready(self):
self.relation_ids.return_value = ['ironic-api:0']
self.related_units.return_value = 'ironic-api/0'
self.test_relation.set({
'ironic-api-ready': True,
})
self.assertEqual(
context.IronicAPIContext()(),
{'ironic_api_ready': True})
def test_ironic_api_not_ready(self):
self.relation_ids.return_value = ['ironic-api:0']
self.related_units.return_value = 'ironic-api/0'
self.test_relation.set({
'ready': False,
})
self.assertEqual(
context.IronicAPIContext()(), {})
class SerialConsoleContextTests(CharmTestCase):
def setUp(self):
super(SerialConsoleContextTests, self).setUp(context, TO_PATCH)
self.relation_get.side_effect = self.test_relation.get
self.config.side_effect = self.test_config.get
self.host_uuid = 'e46e530d-18ae-4a67-9ff0-e6e2ba7c60a7'
def test_serial_console_disabled(self):
self.relation_ids.return_value = ['cloud-compute:0']
self.related_units.return_value = 'nova-cloud-controller/0'
self.test_relation.set({
'enable_serial_console': 'false',
})
self.assertEqual(
context.SerialConsoleContext()(),
{'enable_serial_console': 'false',
'serial_console_base_url': 'ws://127.0.0.1:6083/'}
)
def test_serial_console_not_provided(self):
self.relation_ids.return_value = ['cloud-compute:0']
self.related_units.return_value = 'nova-cloud-controller/0'
self.test_relation.set({
'enable_serial_console': None,
})
self.assertEqual(
context.SerialConsoleContext()(),
{'enable_serial_console': 'false',
'serial_console_base_url': 'ws://127.0.0.1:6083/'}
)
def test_serial_console_provided(self):
self.relation_ids.return_value = ['cloud-compute:0']
self.related_units.return_value = 'nova-cloud-controller/0'
self.test_relation.set({
'enable_serial_console': 'true',
'serial_console_base_url': 'ws://10.10.10.1:6083/'
})
self.assertEqual(
context.SerialConsoleContext()(),
{'enable_serial_console': 'true',
'serial_console_base_url': 'ws://10.10.10.1:6083/'}
)
def test_libvirt_use_multipath(self):
self.kv.return_value = FakeUnitdata(**{'host_uuid': self.host_uuid})
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'yakkety'}
self.os_release.return_value = 'ocata'
self.test_config.set('use-multipath', True)
libvirt = context.NovaComputeLibvirtContext()
self.assertEqual(
{'libvirtd_opts': '',
'libvirt_user': 'libvirt',
'use_multipath': True,
'arch': platform.machine(),
'ksm': 'AUTO',
'kvm_hugepages': 0,
'listen_tls': 0,
'host_uuid': self.host_uuid,
'force_raw_images': True,
'inject_password': False,
'inject_partition': -2,
'block_device_allocate_retries': 300,
'default_ephemeral_format': 'ext4',
'reserved_host_disk': 0,
'reserved_host_memory': 512}, libvirt())
class NovaComputeAvailabilityZoneContextTests(CharmTestCase):
def setUp(self):
super(NovaComputeAvailabilityZoneContextTests,
self).setUp(context, TO_PATCH)
self.os_release.return_value = 'kilo'
@patch('nova_compute_context.config')
@patch('os.environ.get')
def test_availability_zone_no_juju_with_env(self, mock_get,
mock_config):
def environ_get_side_effect(key):
return {
'JUJU_AVAILABILITY_ZONE': 'az1',
}[key]
mock_get.side_effect = environ_get_side_effect
def config_side_effect(key):
return {
'customize-failure-domain': False,
'default-availability-zone': 'nova',
}[key]
mock_config.side_effect = config_side_effect
az_context = context.NovaComputeAvailabilityZoneContext()
self.assertEqual(
{'default_availability_zone': 'nova'}, az_context())
@patch('nova_compute_context.config')
@patch('os.environ.get')
def test_availability_zone_no_juju_no_env(self, mock_get,
mock_config):
def environ_get_side_effect(key):
return {
'JUJU_AVAILABILITY_ZONE': '',
}[key]
mock_get.side_effect = environ_get_side_effect
def config_side_effect(key):
return {
'customize-failure-domain': False,
'default-availability-zone': 'nova',
}[key]
mock_config.side_effect = config_side_effect
az_context = context.NovaComputeAvailabilityZoneContext()
self.assertEqual(
{'default_availability_zone': 'nova'}, az_context())
@patch('os.environ.get')
def test_availability_zone_juju(self, mock_get):
def environ_get_side_effect(key):
return {
'JUJU_AVAILABILITY_ZONE': 'az1',
}[key]
mock_get.side_effect = environ_get_side_effect
self.config.side_effect = self.test_config.get
self.test_config.set('customize-failure-domain', True)
az_context = context.NovaComputeAvailabilityZoneContext()
self.assertEqual(
{'default_availability_zone': 'az1'}, az_context())
class InstanceConsoleContextTest(CharmTestCase):
def setUp(self):
super(InstanceConsoleContextTest, self).setUp(context, TO_PATCH)
self.os_release.return_value = 'mitaka'
@patch.object(context, 'resolve_address')
@patch.object(context, 'relation_ids')
@patch.object(context, 'related_units')
def test_spice(self,
mock_related_units,
mock_relation_ids,
mock_resolve_address):
mock_relation_ids.return_value = ['cloud-compute:15']
mock_related_units.return_value = ['nova-compute/0']
mock_resolve_address.return_value = "internal-address"
rel_settings = {
'console_access_protocol': 'spice',
'spice_agent_enabled': True,
'console_keymap': 'en-us',
'console_proxy_spice_address': 'http://1.2.3.4:56/spice_auto.html',
'console_proxy_spice_host': '1.2.3.4',
'console_proxy_spice_port': '56',
}
def rel_get(key, rid, unit):
return rel_settings[key]
self.relation_get.side_effect = rel_get
ctxt = context.InstanceConsoleContext()()
self.assertEqual(ctxt['spice_agent_enabled'], True, str(ctxt))
@patch.object(context.platform, 'machine')
@patch.object(context, 'resolve_address')
@patch.object(context, 'relation_ids')
@patch.object(context, 'related_units')
def test_spice_s390x(self, mock_related_units, mock_relation_ids,
mock_resolve_address, mock_machine):
mock_relation_ids.return_value = ['cloud-compute:15']
mock_related_units.return_value = ['nova-compute/0']
mock_resolve_address.return_value = "internal-address"
mock_machine.return_value = "s390x"
rel_settings = {
'console_access_protocol': 'spice',
'spice_agent_enabled': True,
'console_keymap': 'en-us',
'console_proxy_spice_address': 'http://1.2.3.4:56/spice_auto.html',
'console_proxy_spice_host': '1.2.3.4',
'console_proxy_spice_port': '56',
}
def rel_get(key, rid, unit):
return rel_settings[key]
self.relation_get.side_effect = rel_get
ctxt = context.InstanceConsoleContext()()
self.assertEqual(ctxt, {})
class NovaComputeCephContextTest(CharmTestCase):
def setUp(self):
super().setUp(context, TO_PATCH)
self.config.side_effect = self.test_config.get
self.os_release.return_value = 'queens'
@patch('nova_compute_context.sent_ceph_application_name')
@patch('charmhelpers.contrib.openstack.context.CephContext.__call__')
def test_secret_uuid_old(self, mock_call, sent_name):
sent_name.return_value = 'nova-compute-kvm'
mock_call.return_value = {'foo': 'bar'}
ctxt = context.NovaComputeCephContext()()
self.assertEqual(
context.CEPH_OLD_SECRET_UUID, ctxt['ceph_secret_uuid'])
self.assertEqual(
context.CEPH_OLD_SECRET_UUID, ctxt['rbd_secret_uuid'])
self.assertEqual('nova-compute-kvm', ctxt['service_name'])
self.assertEqual('nova-compute-kvm', ctxt['rbd_user'])
@patch('nova_compute_context.sent_ceph_application_name')
@patch('charmhelpers.contrib.openstack.context.CephContext.__call__')
def test_secret_uuid_old_2(self, mock_call, sent_name):
sent_name.return_value = 'nova-compute'
mock_call.return_value = {'foo': 'bar'}
ctxt = context.NovaComputeCephContext()()
self.assertEqual(
context.CEPH_OLD_SECRET_UUID, ctxt['ceph_secret_uuid'])
self.assertEqual(
context.CEPH_OLD_SECRET_UUID, ctxt['rbd_secret_uuid'])
self.assertEqual('nova-compute', ctxt['service_name'])
self.assertEqual('nova-compute', ctxt['rbd_user'])
@patch('nova_compute_context.sent_ceph_application_name')
@patch('charmhelpers.contrib.openstack.context.CephContext.__call__')
def test_secret_uuid_new(self, mock_call, sent_name):
sent_name.return_value = context.CEPH_AUTH_CRED_NAME
mock_call.return_value = {'foo': 'bar'}
ctxt = context.NovaComputeCephContext()()
self.assertEqual(context.CEPH_SECRET_UUID, ctxt['ceph_secret_uuid'])
self.assertEqual(context.CEPH_SECRET_UUID, ctxt['rbd_secret_uuid'])
self.assertEqual(context.CEPH_AUTH_CRED_NAME, ctxt['service_name'])
self.assertEqual(context.CEPH_AUTH_CRED_NAME, ctxt['rbd_user'])
@patch.dict(context.os.environ, {'JUJU_UNIT_NAME': 'nova_compute'},
clear=True)
@patch('charmhelpers.contrib.openstack.context.CephContext.__call__')
def test_rbd_replicated_pool(self, mock_call):
mock_call.return_value = {'mon_hosts': 'foo,bar'}
ctxt = context.NovaComputeCephContext()()
self.assertEqual(ctxt['rbd_pool'], 'nova')
@patch.dict(context.os.environ, {'JUJU_UNIT_NAME': 'nova_compute'},
clear=True)
@patch('charmhelpers.contrib.openstack.context.CephContext.__call__')
def test_rbd_ec_pool(self, mock_call):
self.test_config.set('pool-type', 'erasure-coded')
mock_call.return_value = {'mon_hosts': 'foo,bar'}
ctxt = context.NovaComputeCephContext()()
self.assertEqual(ctxt['rbd_pool'], 'nova-metadata')
self.test_config.set('ec-rbd-metadata-pool', 'nova-newmetadata')
ctxt = context.NovaComputeCephContext()()
self.assertEqual(ctxt['rbd_pool'], 'nova-newmetadata')
class NeutronPluginSubordinateConfigContextTest(CharmTestCase):
def setUp(self):
super().setUp(context, TO_PATCH)
@patch('charmhelpers.contrib.openstack.context.relation_ids')
def test_context_complete(self, mock_relation_ids):
mock_relation_ids.return_value = []
ctxt = context.NeutronPluginSubordinateConfigContext(
interface=['neutron-plugin'],
service=['nova-compute', 'nova'],
config_file='/etc/nova.conf')
self.assertFalse(ctxt.context_complete({}))
self.assertTrue(ctxt.context_complete({'sections': {}}))
class NovaComputePlacementContextTest(CharmTestCase):
def setUp(self):
super(NovaComputePlacementContextTest, self).setUp(context, TO_PATCH)
self.config.side_effect = self.test_config.get
self.os_release.return_value = 'train'
self.maxDiff = None
def test_allocation_ratio(self):
self.test_config.set('cpu-allocation-ratio', 64)
self.test_config.set('ram-allocation-ratio', 32.3)
self.test_config.set('disk-allocation-ratio', 16)
ctxt = context.NovaComputePlacementContext()
self.assertEqual(
{'cpu_allocation_ratio': 64,
'ram_allocation_ratio': 32.3,
'disk_allocation_ratio': 16,
'initial_cpu_allocation_ratio': None,
'initial_ram_allocation_ratio': None,
'initial_disk_allocation_ratio': None}, ctxt())
def test_allocation_ratio_defaults_pre_stein(self):
_allocation_ratios = {
'cpu_allocation_ratio': 8,
'ram_allocation_ratio': 24,
'disk_allocation_ratio': 32,
}
self.os_release.return_value = 'queens'
self.relation_ids.return_value = ['cloud-compute:0']
self.related_units.return_value = ['nova-cloud-controller/0']
self.relation_get.side_effect = (
lambda k, **kwargs: _allocation_ratios.get(k)
)
ctxt = context.NovaComputePlacementContext()
self.assertEqual(
{'cpu_allocation_ratio': 8,
'ram_allocation_ratio': 24,
'disk_allocation_ratio': 32,
'initial_cpu_allocation_ratio': None,
'initial_ram_allocation_ratio': None,
'initial_disk_allocation_ratio': None}, ctxt())
def test_allocation_ratio_defaults(self):
_allocation_ratios = {
'cpu_allocation_ratio': 8,
'ram_allocation_ratio': 24,
'disk_allocation_ratio': 32,
}
self.os_release.return_value = 'ussuri'
self.relation_ids.return_value = ['cloud-compute:0']
self.related_units.return_value = ['nova-cloud-controller/0']
self.relation_get.side_effect = (
lambda k, **kwargs: _allocation_ratios.get(k)
)
ctxt = context.NovaComputePlacementContext()
self.assertEqual(
{'cpu_allocation_ratio': None,
'ram_allocation_ratio': None,
'disk_allocation_ratio': None,
'initial_cpu_allocation_ratio': 8,
'initial_ram_allocation_ratio': 24,
'initial_disk_allocation_ratio': 32}, ctxt())
class NovaComputeSWTPMContextTest(CharmTestCase):
def setUp(self):
super(NovaComputeSWTPMContextTest, self).setUp(context, TO_PATCH)
self.config.side_effect = self.test_config.get
self.os_release.return_value = 'wallaby'
self.maxDiff = None
def test_before_wallaby(self):
"""Tests context values indicate swtpm disabled prior to Wallaby"""
self.os_release.return_value = 'victoria'
self.test_config.set('enable-vtpm', True)
ctxt = context.NovaComputeSWTPMContext()
self.assertEqual({}, ctxt())
def test_wallaby_or_later_enabled(self):
"""Tests context values after Wallaby with vtpm enabled"""
self.test_config.set('enable-vtpm', True)
for stack_release in ['wallaby', 'xena']:
self.os_release.return_value = stack_release
ctxt = context.NovaComputeSWTPMContext()
self.assertEqual({
'swtpm_enabled': True,
}, ctxt(), msg=stack_release)
def test_wallaby_disabled(self):
"""Tests context values when config says don't do, but version is
capable."""
self.test_config.set('enable-vtpm', False)
ctxt = context.NovaComputeSWTPMContext()
self.assertEqual({
'swtpm_enabled': False,
}, ctxt())
class NovaComputeVirtMkfsContext(CharmTestCase):
def setUp(self):
super(NovaComputeVirtMkfsContext, self).setUp(context, TO_PATCH)
self.config.side_effect = self.test_config.get
self.os_release.return_value = 'zed'
def test_cfg_none(self):
self.test_config.set('virt-mkfs-cmds', None)
ctxt = context.VirtMkfsContext()
self.assertEqual({}, ctxt())
def test_cfg_single(self):
self.test_config.set('virt-mkfs-cmds', 'default=mkfs.vfat')
ctxt = context.VirtMkfsContext()
self.assertEqual({'virt_mkfs': 'virt_mkfs = default=mkfs.vfat'},
ctxt())
def test_cfg_multi(self):
self.test_config.set('virt-mkfs-cmds',
'default=mkfs.ext4,windows=mkfs.ntfs')
ctxt = context.VirtMkfsContext()
self.assertEqual({'virt_mkfs': ('virt_mkfs = default=mkfs.ext4\n'
'virt_mkfs = windows=mkfs.ntfs')},
ctxt())
class TestNovaComputeHostInfoContext(CharmTestCase):
def setUp(self):
super().setUp(context, TO_PATCH)
self.config.side_effect = self.test_config.get
self.os_release.return_value = 'ussuri'
def test_use_fqdn_hint(self):
self.kv().get.return_value = False
ctxt = context.NovaComputeHostInfoContext
self.assertEqual(ctxt._use_fqdn_hint(), False)
self.kv().get.return_value = True
self.assertEqual(ctxt._use_fqdn_hint(), True)
def test_set_fqdn_hint(self):
context.NovaComputeHostInfoContext.set_fqdn_hint(True)
self.kv().set.assert_called_with(
context.NovaComputeHostInfoContext.USE_FQDN_KEY, True
)
def test_set_record_fqdn_hint(self):
context.NovaComputeHostInfoContext.set_record_fqdn_hint(True)
self.kv().set.assert_called_with(
context.NovaComputeHostInfoContext.RECORD_FQDN_KEY, True
)
def test_get_record_fqdn_hint(self):
self.kv().get.side_effect = dict().get
self.assertFalse(
context.NovaComputeHostInfoContext.get_record_fqdn_hint()
)
data = {context.NovaComputeHostInfoContext.RECORD_FQDN_KEY: True}
self.kv().get.side_effect = lambda x, y: data[x]
self.assertTrue(
context.NovaComputeHostInfoContext.get_record_fqdn_hint()
)
@patch('socket.getaddrinfo')
@patch('socket.gethostname')
def test_get_canonical_name_gethostname(self, gethostname, getaddrinfo):
gethostname.return_value = 'bar'
def raise_oserror(name, *args, **kwargs):
self.assertEqual(name, 'bar')
raise OSError()
getaddrinfo.side_effect = raise_oserror
data = {
context.NovaComputeHostInfoContext.USE_FQDN_KEY: True,
context.NovaComputeHostInfoContext.RECORD_FQDN_KEY: True,
}
self.kv().get.side_effect = lambda x, y: data.get(x, y)
self.kv().set.side_effect = lambda x, y: data.__setitem__(x, y)
ctxt = context.NovaComputeHostInfoContext()
self.assertEqual(ctxt._get_canonical_name('bar'), '')
def fake_getaddrinfo(name, *args, **kwargs):
self.assertEqual(name, 'foobar')
return [[0, 1, 2, 'bar.example.com']]
getaddrinfo.reset_mock()
getaddrinfo.side_effect = fake_getaddrinfo
self.assertEqual(ctxt._get_canonical_name('foobar'), 'bar.example.com')
gethostname.return_value = 'foobar'
self.assertEqual(ctxt(),
{'host_fqdn': 'bar.example.com',
'host': 'foobar',
'use_fqdn_hint': True})
@patch('socket.getaddrinfo')
@patch('socket.gethostname')
def test_call_unstable_hostname(self, gethostname, getaddrinfo):
def raise_oserror(name, *args, **kwargs):
raise OSError()
def fake_getaddrinfo(name, *args, **kwargs):
return [[0, 1, 2, 'bar.example.com']]
getaddrinfo.side_effect = raise_oserror
gethostname.return_value = 'bar'
data = {
context.NovaComputeHostInfoContext.USE_FQDN_KEY: True,
context.NovaComputeHostInfoContext.RECORD_FQDN_KEY: True,
}
self.kv().get.side_effect = lambda x, y: data.get(x, y)
self.kv().set.side_effect = lambda x, y: data.__setitem__(x, y)
ctxt = context.NovaComputeHostInfoContext()
self.assertEqual(ctxt(),
{'host_fqdn': 'bar',
'host': 'bar',
'use_fqdn_hint': True})
# After the first run socket.getaddrinfo() returns a valid fqdn
# provided by the DNS, but by this time the host_fqdn is stored and
# re-used.
getaddrinfo.reset_mock()
getaddrinfo.side_effect = fake_getaddrinfo
self.assertEqual(ctxt(),
{'host_fqdn': 'bar',
'host': 'bar',
'use_fqdn_hint': True})
getaddrinfo.assert_not_called()