Add Ironic virt type
Adds support for the Ironic virt driver. Change-Id: I72a7fb65395e4ceddc77a92bccc7b4563af0750a
This commit is contained in:
1
hooks/ironic-api-relation-changed
Symbolic link
1
hooks/ironic-api-relation-changed
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
nova_compute_hooks.py
|
||||||
@@ -341,6 +341,21 @@ class NovaComputeVirtContext(context.OSContextGenerator):
|
|||||||
return ctxt
|
return ctxt
|
||||||
|
|
||||||
|
|
||||||
|
class IronicAPIContext(context.OSContextGenerator):
|
||||||
|
interfaces = ["ironic-api"]
|
||||||
|
|
||||||
|
def __call__(self):
|
||||||
|
ctxt = {}
|
||||||
|
for rid in relation_ids('ironic-api'):
|
||||||
|
for unit in related_units(rid):
|
||||||
|
is_ready = relation_get(
|
||||||
|
'ironic-api-ready', rid=rid, unit=unit)
|
||||||
|
if is_ready:
|
||||||
|
ctxt["ironic_api_ready"] = is_ready
|
||||||
|
return ctxt
|
||||||
|
return ctxt
|
||||||
|
|
||||||
|
|
||||||
def assert_libvirt_rbd_imagebackend_allowed():
|
def assert_libvirt_rbd_imagebackend_allowed():
|
||||||
os_rel = "Juno"
|
os_rel = "Juno"
|
||||||
os_ver = get_os_version_package('nova-common')
|
os_ver = get_os_version_package('nova-common')
|
||||||
|
|||||||
@@ -364,6 +364,12 @@ def compute_changed():
|
|||||||
import_keystone_ca_cert()
|
import_keystone_ca_cert()
|
||||||
|
|
||||||
|
|
||||||
|
@hooks.hook('ironic-api-relation-changed')
|
||||||
|
@restart_on_change(restart_map())
|
||||||
|
def ironic_api_changed():
|
||||||
|
CONFIGS.write(NOVA_CONF)
|
||||||
|
|
||||||
|
|
||||||
@hooks.hook('ceph-access-relation-joined')
|
@hooks.hook('ceph-access-relation-joined')
|
||||||
@hooks.hook('ceph-relation-joined')
|
@hooks.hook('ceph-relation-joined')
|
||||||
@restart_on_change(restart_map())
|
@restart_on_change(restart_map())
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ from nova_compute_context import (
|
|||||||
NovaComputeCephContext,
|
NovaComputeCephContext,
|
||||||
NeutronComputeContext,
|
NeutronComputeContext,
|
||||||
InstanceConsoleContext,
|
InstanceConsoleContext,
|
||||||
|
IronicAPIContext,
|
||||||
CEPH_CONF,
|
CEPH_CONF,
|
||||||
ceph_config_file,
|
ceph_config_file,
|
||||||
HostIPContext,
|
HostIPContext,
|
||||||
@@ -170,6 +171,7 @@ LIBVIRTD_CONF = '/etc/libvirt/libvirtd.conf'
|
|||||||
LIBVIRT_BIN = '/etc/default/libvirt-bin'
|
LIBVIRT_BIN = '/etc/default/libvirt-bin'
|
||||||
LIBVIRT_BIN_OVERRIDES = '/etc/init/libvirt-bin.override'
|
LIBVIRT_BIN_OVERRIDES = '/etc/init/libvirt-bin.override'
|
||||||
NOVA_CONF = '%s/nova.conf' % NOVA_CONF_DIR
|
NOVA_CONF = '%s/nova.conf' % NOVA_CONF_DIR
|
||||||
|
NOVA_COMPUTE_CONF = '%s/nova-compute.conf' % NOVA_CONF_DIR
|
||||||
VENDORDATA_FILE = '%s/vendor_data.json' % NOVA_CONF_DIR
|
VENDORDATA_FILE = '%s/vendor_data.json' % NOVA_CONF_DIR
|
||||||
QEMU_KVM = '/etc/default/qemu-kvm'
|
QEMU_KVM = '/etc/default/qemu-kvm'
|
||||||
NOVA_API_AA_PROFILE_PATH = ('/etc/apparmor.d/{}'.format(NOVA_API_AA_PROFILE))
|
NOVA_API_AA_PROFILE_PATH = ('/etc/apparmor.d/{}'.format(NOVA_API_AA_PROFILE))
|
||||||
@@ -203,6 +205,7 @@ BASE_RESOURCE_MAP = {
|
|||||||
context.OSConfigFlagContext(),
|
context.OSConfigFlagContext(),
|
||||||
CloudComputeContext(),
|
CloudComputeContext(),
|
||||||
LxdContext(),
|
LxdContext(),
|
||||||
|
IronicAPIContext(),
|
||||||
NovaComputeLibvirtContext(),
|
NovaComputeLibvirtContext(),
|
||||||
NovaComputeCephContext(),
|
NovaComputeCephContext(),
|
||||||
context.SyslogContext(),
|
context.SyslogContext(),
|
||||||
@@ -292,6 +295,7 @@ VIRT_TYPES = {
|
|||||||
'uml': ['nova-compute-uml'],
|
'uml': ['nova-compute-uml'],
|
||||||
'lxc': ['nova-compute-lxc'],
|
'lxc': ['nova-compute-lxc'],
|
||||||
'lxd': ['nova-compute-lxd'],
|
'lxd': ['nova-compute-lxd'],
|
||||||
|
'ironic': ['nova-compute-ironic'],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -332,7 +336,8 @@ def resource_map():
|
|||||||
hook execution.
|
hook execution.
|
||||||
'''
|
'''
|
||||||
# TODO: Cache this on first call?
|
# TODO: Cache this on first call?
|
||||||
if config('virt-type').lower() == 'lxd':
|
virt_type = config('virt-type').lower()
|
||||||
|
if virt_type in ('lxd', 'ironic'):
|
||||||
resource_map = deepcopy(BASE_RESOURCE_MAP)
|
resource_map = deepcopy(BASE_RESOURCE_MAP)
|
||||||
else:
|
else:
|
||||||
resource_map = deepcopy(LIBVIRT_RESOURCE_MAP)
|
resource_map = deepcopy(LIBVIRT_RESOURCE_MAP)
|
||||||
@@ -363,6 +368,16 @@ def resource_map():
|
|||||||
resource_map.pop(NOVA_API_AA_PROFILE_PATH)
|
resource_map.pop(NOVA_API_AA_PROFILE_PATH)
|
||||||
resource_map.pop(NOVA_NETWORK_AA_PROFILE_PATH)
|
resource_map.pop(NOVA_NETWORK_AA_PROFILE_PATH)
|
||||||
|
|
||||||
|
if virt_type == 'ironic':
|
||||||
|
# NOTE(gsamfira): OpenStack versions prior to Victoria do not have a
|
||||||
|
# dedicated nova-compute-ironic package which provides a suitable
|
||||||
|
# nova-compute.conf file. We use a template to compensate for that.
|
||||||
|
if cmp_os_release < 'victoria':
|
||||||
|
resource_map[NOVA_COMPUTE_CONF] = {
|
||||||
|
"services": ["nova-compute"],
|
||||||
|
"contexts": [],
|
||||||
|
}
|
||||||
|
|
||||||
cmp_distro_codename = CompareHostReleases(
|
cmp_distro_codename = CompareHostReleases(
|
||||||
lsb_release()['DISTRIB_CODENAME'].lower())
|
lsb_release()['DISTRIB_CODENAME'].lower())
|
||||||
if (cmp_distro_codename >= 'yakkety' or cmp_os_release >= 'ocata'):
|
if (cmp_distro_codename >= 'yakkety' or cmp_os_release >= 'ocata'):
|
||||||
@@ -391,7 +406,8 @@ def resource_map():
|
|||||||
# NOTE(james-page): If not on an upstart based system, don't write
|
# NOTE(james-page): If not on an upstart based system, don't write
|
||||||
# and override file for libvirt-bin.
|
# and override file for libvirt-bin.
|
||||||
if not os.path.exists('/etc/init'):
|
if not os.path.exists('/etc/init'):
|
||||||
del resource_map[LIBVIRT_BIN_OVERRIDES]
|
if LIBVIRT_BIN_OVERRIDES in resource_map:
|
||||||
|
del resource_map[LIBVIRT_BIN_OVERRIDES]
|
||||||
|
|
||||||
return resource_map
|
return resource_map
|
||||||
|
|
||||||
@@ -463,6 +479,18 @@ def determine_packages():
|
|||||||
packages.append('ceph-common')
|
packages.append('ceph-common')
|
||||||
|
|
||||||
virt_type = config('virt-type')
|
virt_type = config('virt-type')
|
||||||
|
if virt_type == 'ironic' and release < 'victoria':
|
||||||
|
# ironic compute driver is part of nova and
|
||||||
|
# gets installed allong with python3-nova
|
||||||
|
# The nova-compute-ironic metapackage that satisfies
|
||||||
|
# nova-compute-hypervisor does not exist for versions of
|
||||||
|
# OpenStack prior to Victoria. Use nova-compute-vmware,
|
||||||
|
# as that package has the least amount of dependencies.
|
||||||
|
# We also add python3-ironicclient here. This is a dependency
|
||||||
|
# which gets installed by nova-compute-ironic in Victoria and later.
|
||||||
|
VIRT_TYPES[virt_type] = [
|
||||||
|
'nova-compute-vmware',
|
||||||
|
'python3-ironicclient']
|
||||||
try:
|
try:
|
||||||
packages.extend(VIRT_TYPES[virt_type])
|
packages.extend(VIRT_TYPES[virt_type])
|
||||||
except KeyError:
|
except KeyError:
|
||||||
@@ -876,6 +904,8 @@ def get_optional_relations():
|
|||||||
optional_interfaces['neutron-plugin'] = ['neutron-plugin']
|
optional_interfaces['neutron-plugin'] = ['neutron-plugin']
|
||||||
if config('encrypt'):
|
if config('encrypt'):
|
||||||
optional_interfaces['vault'] = ['secrets-storage']
|
optional_interfaces['vault'] = ['secrets-storage']
|
||||||
|
if config('virt-type').lower() == 'ironic':
|
||||||
|
optional_interfaces['baremetal'] = ['ironic-api']
|
||||||
|
|
||||||
return optional_interfaces
|
return optional_interfaces
|
||||||
|
|
||||||
|
|||||||
@@ -53,6 +53,8 @@ requires:
|
|||||||
interface: keystone-credentials
|
interface: keystone-credentials
|
||||||
secrets-storage:
|
secrets-storage:
|
||||||
interface: vault-kv
|
interface: vault-kv
|
||||||
|
ironic-api:
|
||||||
|
interface: baremetal
|
||||||
peers:
|
peers:
|
||||||
compute-peer:
|
compute-peer:
|
||||||
interface: nova
|
interface: nova
|
||||||
|
|||||||
15
templates/parts/section-ironic
Normal file
15
templates/parts/section-ironic
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{% if virt_type == 'ironic' and auth_host and ironic_api_ready -%}
|
||||||
|
{% if api_version and api_version == "3" -%}
|
||||||
|
{% set auth_ver = "v3" -%}
|
||||||
|
{% else -%}
|
||||||
|
{% set auth_ver = "v2.0" -%}
|
||||||
|
{% endif -%}
|
||||||
|
[ironic]
|
||||||
|
auth_type = password
|
||||||
|
auth_url = {{auth_protocol}}://{{auth_host}}:{{auth_port}}/{{auth_ver}}
|
||||||
|
project_name = {{ admin_tenant_name }}
|
||||||
|
username = {{ admin_user }}
|
||||||
|
password = {{ admin_password }}
|
||||||
|
project_domain_name = {{ admin_domain_name }}
|
||||||
|
user_domain_name = {{ admin_domain_name }}
|
||||||
|
{% endif -%}
|
||||||
2
templates/train/nova-compute.conf
Normal file
2
templates/train/nova-compute.conf
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
[DEFAULT]
|
||||||
|
compute_driver=ironic.IronicDriver
|
||||||
@@ -316,6 +316,8 @@ disable_libvirt_livesnapshot = False
|
|||||||
|
|
||||||
{% include "parts/section-placement" %}
|
{% include "parts/section-placement" %}
|
||||||
|
|
||||||
|
{% include "parts/section-ironic" %}
|
||||||
|
|
||||||
[compute]
|
[compute]
|
||||||
{% if cpu_shared_set -%}
|
{% if cpu_shared_set -%}
|
||||||
cpu_shared_set = {{ cpu_shared_set }}
|
cpu_shared_set = {{ cpu_shared_set }}
|
||||||
|
|||||||
@@ -767,6 +767,37 @@ class NovaComputeContextTests(CharmTestCase):
|
|||||||
'pcid, vmx, pdpe1gb')
|
'pcid, vmx, pdpe1gb')
|
||||||
|
|
||||||
|
|
||||||
|
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):
|
class SerialConsoleContextTests(CharmTestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
|||||||
@@ -101,6 +101,31 @@ class NovaComputeUtilsTests(CharmTestCase):
|
|||||||
]
|
]
|
||||||
self.assertTrue(ex == result)
|
self.assertTrue(ex == result)
|
||||||
|
|
||||||
|
@patch.object(utils, 'nova_metadata_requirement')
|
||||||
|
def test_determine_packages_ironic(self, en_meta):
|
||||||
|
self.os_release.return_value = 'victoria'
|
||||||
|
self.test_config.set('virt-type', 'ironic')
|
||||||
|
en_meta.return_value = (False, None)
|
||||||
|
self.relation_ids.return_value = []
|
||||||
|
result = utils.determine_packages()
|
||||||
|
ex = utils.BASE_PACKAGES + [
|
||||||
|
'nova-compute-ironic'
|
||||||
|
]
|
||||||
|
self.assertTrue(ex.sort() == result.sort())
|
||||||
|
|
||||||
|
@patch.object(utils, 'nova_metadata_requirement')
|
||||||
|
def test_determine_packages_ironic_pre_victoria(self, en_meta):
|
||||||
|
self.os_release.return_value = 'train'
|
||||||
|
self.test_config.set('virt-type', 'ironic')
|
||||||
|
en_meta.return_value = (False, None)
|
||||||
|
self.relation_ids.return_value = []
|
||||||
|
result = utils.determine_packages()
|
||||||
|
ex = utils.BASE_PACKAGES + [
|
||||||
|
'nova-compute-vmware',
|
||||||
|
'python3-ironicclient'
|
||||||
|
]
|
||||||
|
self.assertTrue(ex.sort() == result.sort())
|
||||||
|
|
||||||
@patch.object(utils, 'nova_metadata_requirement')
|
@patch.object(utils, 'nova_metadata_requirement')
|
||||||
@patch.object(utils, 'network_manager')
|
@patch.object(utils, 'network_manager')
|
||||||
@patch('platform.machine')
|
@patch('platform.machine')
|
||||||
@@ -526,6 +551,28 @@ class NovaComputeUtilsTests(CharmTestCase):
|
|||||||
result = utils.resource_map()['/etc/nova/nova.conf']['services']
|
result = utils.resource_map()['/etc/nova/nova.conf']['services']
|
||||||
self.assertTrue('nova-api-metadata' in result)
|
self.assertTrue('nova-api-metadata' in result)
|
||||||
|
|
||||||
|
@patch.object(utils, 'nova_metadata_requirement')
|
||||||
|
def test_resource_map_ironic_pre_victoria(self, _metadata):
|
||||||
|
_metadata.return_value = (True, None)
|
||||||
|
self.relation_ids.return_value = []
|
||||||
|
self.os_release.return_value = 'train'
|
||||||
|
self.test_config.set('virt-type', 'ironic')
|
||||||
|
result = utils.resource_map()
|
||||||
|
self.assertTrue(utils.NOVA_COMPUTE_CONF in result)
|
||||||
|
self.assertEqual(
|
||||||
|
result[utils.NOVA_COMPUTE_CONF]["services"], ["nova-compute"])
|
||||||
|
self.assertEqual(
|
||||||
|
result[utils.NOVA_COMPUTE_CONF]["contexts"], [])
|
||||||
|
|
||||||
|
@patch.object(utils, 'nova_metadata_requirement')
|
||||||
|
def test_resource_map_ironic(self, _metadata):
|
||||||
|
_metadata.return_value = (True, None)
|
||||||
|
self.relation_ids.return_value = []
|
||||||
|
self.os_release.return_value = 'victoria'
|
||||||
|
self.test_config.set('virt-type', 'ironic')
|
||||||
|
result = utils.resource_map()
|
||||||
|
self.assertTrue(utils.NOVA_COMPUTE_CONF not in result)
|
||||||
|
|
||||||
def fake_user(self, username='foo'):
|
def fake_user(self, username='foo'):
|
||||||
user = MagicMock()
|
user = MagicMock()
|
||||||
user.pw_dir = '/home/' + username
|
user.pw_dir = '/home/' + username
|
||||||
|
|||||||
Reference in New Issue
Block a user