Add template rendering in NovaHypervisor
In order to apply dynamically generated virt-type config to the actual templates they need to be rendered. Also improves a KVM presence check since the CPU features may be visible to a container but KVM API via a character file might not be available there. The cpu-mode is now also set to "host-model" instead of "host-passthrough" when emulation is used as it is done in the default config. Closes-Bug: #1942761 Change-Id: I689543232a94f4df16445c6e3057c5a329d3f6ae
This commit is contained in:
parent
42a50992ed
commit
648a45f3d9
@ -183,7 +183,7 @@ class LocalTestHost(TestHost):
|
||||
profile_conf = {
|
||||
'config': {'linux.kernel_modules':
|
||||
'iptable_nat, ip6table_nat, ebtables, openvswitch,'
|
||||
'tap, vhost, vhost_net, vhost_scsi, vhost_vsock',
|
||||
'tap, vhost, vhost_net, vhost_scsi, vhost_vsock, kvm',
|
||||
'security.nesting': 'true',
|
||||
'limits.kernel.memlock': 'unlimited'
|
||||
},
|
||||
@ -193,7 +193,8 @@ class LocalTestHost(TestHost):
|
||||
'vhost-net': {'path': '/dev/vhost-net', 'type': 'unix-char'},
|
||||
'vhost-scsi': {'path': '/dev/vhost-scsi', 'type': 'unix-char'},
|
||||
'vhost-vsock': {'path': '/dev/vhost-vsock',
|
||||
'type': 'unix-char'}
|
||||
'type': 'unix-char'},
|
||||
'kvm': {'path': '/dev/kvm', 'type': 'unix-char'},
|
||||
}
|
||||
}
|
||||
self.run(['sudo', 'lxc', 'profile', 'edit', 'microstack'],
|
||||
|
@ -25,6 +25,8 @@ limitations under the License.
|
||||
|
||||
import json
|
||||
import platform
|
||||
import os
|
||||
import stat
|
||||
|
||||
from time import sleep
|
||||
from os import path
|
||||
@ -463,7 +465,10 @@ class NovaHypervisor(Question):
|
||||
|
||||
def yes(self, answer):
|
||||
log.info('Configuring nova compute hypervisor ...')
|
||||
|
||||
self._maybe_enable_emulation()
|
||||
check('snap-openstack', 'setup')
|
||||
|
||||
enable('libvirtd')
|
||||
enable('virtlogd')
|
||||
enable('nova-compute')
|
||||
@ -478,7 +483,7 @@ class NovaHypervisor(Question):
|
||||
log.info('Checking virtualization extensions presence on the host')
|
||||
# Use KVM if it is supported, alternatively fall back to software
|
||||
# emulation.
|
||||
if self._is_hw_virt_supported():
|
||||
if self._is_hw_virt_supported() and self._is_kvm_api_available():
|
||||
log.info('Hardware virtualization is supported - KVM will be used'
|
||||
' for Nova instances')
|
||||
shell.config_set(**{'config.nova.virt-type': 'kvm'})
|
||||
@ -487,7 +492,32 @@ class NovaHypervisor(Question):
|
||||
log.warning('Hardware virtualization is not supported - software'
|
||||
' emulation will be used for Nova instances')
|
||||
shell.config_set(**{'config.nova.virt-type': 'qemu'})
|
||||
shell.config_set(**{'config.nova.cpu-mode': 'host-passthrough'})
|
||||
shell.config_set(**{'config.nova.cpu-mode': 'host-model'})
|
||||
|
||||
@staticmethod
|
||||
def _is_kvm_api_available():
|
||||
kvm_devpath = '/dev/kvm'
|
||||
if not os.path.exists(kvm_devpath):
|
||||
log.warning(f'{kvm_devpath} does not exist')
|
||||
return False
|
||||
elif not os.access(kvm_devpath, os.R_OK | os.W_OK):
|
||||
log.warning(f'{kvm_devpath} is not RW-accessible')
|
||||
return False
|
||||
kvm_dev = os.stat(kvm_devpath)
|
||||
if not stat.S_ISCHR(kvm_dev.st_mode):
|
||||
log.warning(f'{kvm_devpath} is not a character device')
|
||||
return False
|
||||
major = os.major(kvm_dev.st_rdev)
|
||||
minor = os.minor(kvm_dev.st_rdev)
|
||||
if major != 10:
|
||||
log.warning(
|
||||
f'{kvm_devpath} has an unexpected major number: {major}')
|
||||
return False
|
||||
elif minor != 232:
|
||||
log.warning(
|
||||
f'{kvm_devpath} has an unexpected minor number: {minor}')
|
||||
return False
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def _is_hw_virt_supported():
|
||||
|
79
tools/init/tests/test_questions.py
Normal file
79
tools/init/tests/test_questions.py
Normal file
@ -0,0 +1,79 @@
|
||||
import unittest
|
||||
|
||||
import mock
|
||||
import os
|
||||
import sys
|
||||
|
||||
from init.questions import NovaHypervisor
|
||||
|
||||
sys.path.append(os.getcwd()) # noqa
|
||||
|
||||
|
||||
class TestNovaHypervisor(unittest.TestCase):
|
||||
|
||||
@mock.patch('os.path.exists', return_value=False)
|
||||
def test_is_kvm_api_available_no_kvm_char_file(self, mock_exists):
|
||||
self.assertFalse(NovaHypervisor._is_kvm_api_available())
|
||||
|
||||
@mock.patch('os.access', side_effect=(
|
||||
lambda p, m: False if p == '/dev/kvm' else True))
|
||||
@mock.patch('os.path.exists', return_value=True)
|
||||
def test_is_kvm_api_available_inaccessible_kvm_char_file(
|
||||
self, mock_exists, mock_access):
|
||||
self.assertFalse(NovaHypervisor._is_kvm_api_available())
|
||||
|
||||
@mock.patch('stat.S_ISCHR', side_effect=lambda m: False)
|
||||
@mock.patch('os.stat')
|
||||
@mock.patch('os.access', return_value=True)
|
||||
@mock.patch('os.path.exists', return_value=True)
|
||||
def test_is_kvm_api_available_kvm_file_is_not_char_file(
|
||||
self, mock_exists, mock_access, mock_stat, mock_ischr):
|
||||
self.assertFalse(NovaHypervisor._is_kvm_api_available())
|
||||
|
||||
@mock.patch('os.minor')
|
||||
@mock.patch('os.major')
|
||||
@mock.patch('stat.S_ISCHR', return_value=True)
|
||||
@mock.patch('os.stat')
|
||||
@mock.patch('os.access', return_value=True)
|
||||
@mock.patch('os.path.exists', return_value=True)
|
||||
def test_is_kvm_api_available_kvm_file_invalid_major_minor(
|
||||
self, mock_exists, mock_access, mock_stat, mock_ischr,
|
||||
invalid_major, invalid_minor):
|
||||
self.assertFalse(NovaHypervisor._is_kvm_api_available())
|
||||
|
||||
@mock.patch('os.minor')
|
||||
@mock.patch('os.major', return_value=42)
|
||||
@mock.patch('stat.S_ISCHR', return_value=True)
|
||||
@mock.patch('os.stat')
|
||||
@mock.patch('os.access', return_value=True)
|
||||
@mock.patch('os.path.exists', return_value=True)
|
||||
def test_is_kvm_api_available_kvm_file_invalid_major(
|
||||
self, mock_exists, mock_access, mock_stat, mock_ischr,
|
||||
invalid_major, invalid_minor):
|
||||
self.assertFalse(NovaHypervisor._is_kvm_api_available())
|
||||
|
||||
@mock.patch('os.minor', return_value=42)
|
||||
@mock.patch('os.major', return_value=10)
|
||||
@mock.patch('stat.S_ISCHR', return_value=True)
|
||||
@mock.patch('os.stat')
|
||||
@mock.patch('os.access', return_value=True)
|
||||
@mock.patch('os.path.exists', return_value=True)
|
||||
def test_is_kvm_api_available_kvm_file_invalid_minor(
|
||||
self, mock_exists, mock_access, mock_stat, mock_ischr,
|
||||
invalid_major, invalid_minor):
|
||||
self.assertFalse(NovaHypervisor._is_kvm_api_available())
|
||||
|
||||
@mock.patch('os.minor', return_value=232)
|
||||
@mock.patch('os.major', return_value=10)
|
||||
@mock.patch('stat.S_ISCHR', return_value=True)
|
||||
@mock.patch('os.stat')
|
||||
@mock.patch('os.access', return_value=True)
|
||||
@mock.patch('os.path.exists', return_value=True)
|
||||
def test_is_kvm_api_available_ok(
|
||||
self, mock_exists, mock_access, mock_stat, mock_ischr,
|
||||
invalid_major, invalid_minor):
|
||||
self.assertTrue(NovaHypervisor._is_kvm_api_available())
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
Loading…
x
Reference in New Issue
Block a user