[gnuoy,r=james-page] Add support for Neutron DVR

When Neutron DVR is enabled, nova-compute nodes must run the metadata-api
service for instances on the local hypervisor.
This commit is contained in:
James Page 2015-03-31 08:32:43 +01:00
commit 6155d08997
8 changed files with 112 additions and 4 deletions

View File

@ -393,6 +393,19 @@ class InstanceConsoleContext(context.OSContextGenerator):
return ctxt
class MetadataServiceContext(context.OSContextGenerator):
def __call__(self):
ctxt = {}
for rid in relation_ids('neutron-plugin'):
for unit in related_units(rid):
rdata = relation_get(rid=rid, unit=unit)
if 'metadata-shared-secret' in rdata:
ctxt['metadata_shared_secret'] = \
rdata['metadata-shared-secret']
return ctxt
class NeutronComputeContext(context.NeutronContext):
interfaces = []

View File

@ -21,6 +21,7 @@ from charmhelpers.core.host import (
from charmhelpers.fetch import (
apt_install,
apt_purge,
apt_update,
filter_installed_packages,
)
@ -324,6 +325,18 @@ def update_nrpe_config():
nrpe_setup.write()
@hooks.hook('neutron-plugin-relation-changed')
@restart_on_change(restart_map())
def neutron_plugin_changed():
settings = relation_get()
if 'metadata-shared-secret' in settings:
apt_update()
apt_install('nova-api-metadata', fatal=True)
else:
apt_purge('nova-api-metadata', fatal=True)
CONFIGS.write(NOVA_CONF)
def main():
try:
hooks.execute(sys.argv)

View File

@ -39,6 +39,7 @@ from charmhelpers.contrib.openstack.utils import (
from nova_compute_context import (
CloudComputeContext,
MetadataServiceContext,
NovaComputeLibvirtContext,
NovaComputeCephContext,
NeutronComputeContext,
@ -94,6 +95,7 @@ BASE_RESOURCE_MAP = {
service='nova',
config_file=NOVA_CONF),
InstanceConsoleContext(),
MetadataServiceContext(),
HostIPContext()],
},
}
@ -203,6 +205,8 @@ def resource_map():
}
resource_map.update(CEPH_RESOURCES)
if enable_nova_metadata():
resource_map[NOVA_CONF]['services'].append('nova-api-metadata')
return resource_map
@ -271,6 +275,8 @@ def determine_packages():
except KeyError:
log('Unsupported virt-type configured: %s' % virt_type)
raise
if enable_nova_metadata():
packages.append('nova-api-metadata')
return packages
@ -488,3 +494,8 @@ def assert_charm_supports_ipv6():
if lsb_release()['DISTRIB_CODENAME'].lower() < "trusty":
raise Exception("IPv6 is not supported in the charms for Ubuntu "
"versions less than Trusty 14.04")
def enable_nova_metadata():
ctxt = MetadataServiceContext()()
return 'metadata_shared_secret' in ctxt

View File

@ -38,6 +38,11 @@ my_ip = {{ host_ip }}
glance_api_servers = {{ glance_api_servers }}
{% endif -%}
{% if metadata_shared_secret -%}
neutron_metadata_proxy_shared_secret = {{ metadata_shared_secret }}
service_neutron_metadata_proxy=True
{% endif -%}
{% if console_vnc_type -%}
vnc_enabled = True
novnc_enabled = True

View File

@ -26,6 +26,11 @@ libvirt_use_virtio_for_bridges=False
libvirt_disk_prefix=vd
{% endif -%}
{% if metadata_shared_secret -%}
neutron_metadata_proxy_shared_secret = {{ metadata_shared_secret }}
service_neutron_metadata_proxy=True
{% endif -%}
{% if console_vnc_type -%}
vnc_enabled = True
novnc_enabled = True

View File

@ -233,3 +233,11 @@ class NovaComputeContextTests(CharmTestCase):
self.assertEquals(
{'host_ip': '172.24.0.79'}, host_ip())
self.unit_get.assert_called_with('private-address')
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'})

View File

@ -378,3 +378,12 @@ class NovaComputeRelationsTests(CharmTestCase):
call('/etc/nova/nova.conf'),
]
self.assertEquals(ex, configs.write.call_args_list)
@patch.object(hooks, 'CONFIGS')
def test_neutron_plugin_changed(self, configs):
self.relation_get.return_value = {'metadata-shared-secret':
'sharedsecret'}
hooks.neutron_plugin_changed()
self.assertTrue(self.apt_update.called)
self.apt_install.assert_called_with('nova-api-metadata', fatal=True)
configs.write.assert_called_with('/etc/nova/nova.conf')

View File

@ -24,7 +24,8 @@ TO_PATCH = [
'relation_ids',
'relation_get',
'mkdir',
'install_alternative'
'install_alternative',
'MetadataServiceContext',
]
OVS_PKGS = [
@ -41,8 +42,10 @@ class NovaComputeUtilsTests(CharmTestCase):
super(NovaComputeUtilsTests, self).setUp(utils, TO_PATCH)
self.config.side_effect = self.test_config.get
@patch.object(utils, 'enable_nova_metadata')
@patch.object(utils, 'network_manager')
def test_determine_packages_nova_network(self, net_man):
def test_determine_packages_nova_network(self, net_man, en_meta):
en_meta.return_value = False
net_man.return_value = 'flatdhcpmanager'
self.relation_ids.return_value = []
result = utils.determine_packages()
@ -53,9 +56,11 @@ class NovaComputeUtilsTests(CharmTestCase):
]
self.assertEquals(ex, result)
@patch.object(utils, 'enable_nova_metadata')
@patch.object(utils, 'neutron_plugin')
@patch.object(utils, 'network_manager')
def test_determine_packages_quantum(self, net_man, n_plugin):
def test_determine_packages_quantum(self, net_man, n_plugin, en_meta):
en_meta.return_value = False
self.neutron_plugin_attribute.return_value = OVS_PKGS
net_man.return_value = 'quantum'
n_plugin.return_value = 'ovs'
@ -64,9 +69,11 @@ class NovaComputeUtilsTests(CharmTestCase):
ex = utils.BASE_PACKAGES + OVS_PKGS_FLAT + ['nova-compute-kvm']
self.assertEquals(ex, result)
@patch.object(utils, 'enable_nova_metadata')
@patch.object(utils, 'neutron_plugin')
@patch.object(utils, 'network_manager')
def test_determine_packages_quantum_ceph(self, net_man, n_plugin):
def test_determine_packages_quantum_ceph(self, net_man, n_plugin, en_meta):
en_meta.return_value = False
self.neutron_plugin_attribute.return_value = OVS_PKGS
net_man.return_value = 'quantum'
n_plugin.return_value = 'ovs'
@ -76,6 +83,18 @@ class NovaComputeUtilsTests(CharmTestCase):
['ceph-common', 'nova-compute-kvm'])
self.assertEquals(ex, result)
@patch.object(utils, 'enable_nova_metadata')
@patch.object(utils, 'neutron_plugin')
@patch.object(utils, 'network_manager')
def test_determine_packages_metadata(self, net_man, n_plugin, en_meta):
en_meta.return_value = True
self.neutron_plugin_attribute.return_value = OVS_PKGS
net_man.return_value = 'bob'
n_plugin.return_value = 'ovs'
self.relation_ids.return_value = []
result = utils.determine_packages()
self.assertTrue('nova-api-metadata' in result)
@patch.object(utils, 'network_manager')
def test_resource_map_nova_network_no_multihost(self, net_man):
self.skipTest('skipped until contexts are properly mocked')
@ -172,6 +191,17 @@ class NovaComputeUtilsTests(CharmTestCase):
result = utils.resource_map()
self.assertTrue('/etc/neutron/neutron.conf' not in result)
@patch.object(utils, 'enable_nova_metadata')
@patch.object(utils, 'neutron_plugin')
@patch.object(utils, 'network_manager')
def test_resource_map_metadata(self, net_man, _plugin, _metadata):
_metadata.return_value = True
net_man.return_value = 'bob'
_plugin.return_value = 'ovs'
self.relation_ids.return_value = []
result = utils.resource_map()['/etc/nova/nova.conf']['services']
self.assertTrue('nova-api-metadata' in result)
def fake_user(self, username='foo'):
user = MagicMock()
user.pw_dir = '/home/' + username
@ -375,3 +405,17 @@ class NovaComputeUtilsTests(CharmTestCase):
'secret-set-value', '--secret',
compute_context.CEPH_SECRET_UUID,
'--base64', key])
def test_enable_nova_metadata(self):
class DummyContext():
def __init__(self, return_value):
self.return_value = return_value
def __call__(self):
return self.return_value
self.MetadataServiceContext.return_value = \
DummyContext(return_value={'metadata_shared_secret':
'sharedsecret'})
self.assertEqual(utils.enable_nova_metadata(), True)