Merge "Add binding_profile option for backends"

This commit is contained in:
Jenkins 2016-09-01 20:56:23 +00:00 committed by Gerrit Code Review
commit 345b8021ec
2 changed files with 452 additions and 57 deletions

View File

@ -59,6 +59,30 @@ neutron_bind_network_plugin_opts = [
default=socket.gethostname()),
]
neutron_binding_profile = [
cfg.ListOpt(
"neutron_binding_profiles",
help="A list of binding profiles to be used during port binding. This "
"option can be used with the NeutronBindNetworkPlugin. The value for "
"this option has to be a comma separated list of names that "
"correspond to each binding profile. Each binding profile needs to be "
"specified as an individual configuration section using the binding "
"profile name as the section name."),
]
neutron_binding_profile_opts = [
cfg.StrOpt(
'neutron_switch_id',
help="Switch ID for binding profile."),
cfg.StrOpt(
'neutron_port_id',
help="Port ID on the given switch.",),
cfg.DictOpt(
'neutron_switch_info',
help="Switch label. For example: 'switch_ip: 10.4.30.5'. Multiple "
"key-value pairs separated by commas are accepted.",),
]
CONF = cfg.CONF
@ -284,6 +308,17 @@ class NeutronSingleNetworkPlugin(NeutronNetworkPlugin):
class NeutronBindNetworkPlugin(NeutronNetworkPlugin):
def __init__(self, *args, **kwargs):
super(NeutronBindNetworkPlugin, self).__init__(*args, **kwargs)
self.binding_profiles = []
CONF.register_opts(
neutron_binding_profile,
group=self.neutron_api.config_group_name)
conf = CONF[self.neutron_api.config_group_name]
if conf.neutron_binding_profiles:
for profile in conf.neutron_binding_profiles:
CONF.register_opts(neutron_binding_profile_opts, group=profile)
self.binding_profiles.append(profile)
CONF.register_opts(
neutron_bind_network_plugin_opts,
group=self.neutron_api.config_group_name)
@ -329,6 +364,17 @@ class NeutronBindNetworkPlugin(NeutronNetworkPlugin):
share_network, share_network, device_owner)
arguments['host_id'] = self.config.neutron_host_id
arguments['binding:vnic_type'] = self.config.neutron_vnic_type
if self.binding_profiles:
local_links = []
for profile in self.binding_profiles:
local_links.append({
'switch_id': CONF[profile]['neutron_switch_id'],
'port_id': CONF[profile]['neutron_port_id'],
'switch_info': CONF[profile]['neutron_switch_info'],
})
arguments['binding:profile'] = {
"local_link_information": local_links}
return arguments
def allocate_network(self, context, share_server, share_network=None,

View File

@ -51,6 +51,26 @@ fake_neutron_port = {
"device_id": "fake_device_id",
}
fake_neutron_network = {
'admin_state_up': True,
'availability_zone_hints': [],
'availability_zones': ['nova'],
'description': '',
'id': 'fake net id',
'ipv4_address_scope': None,
'ipv6_address_scope': None,
'name': 'test_neutron_network',
'port_security_enabled': True,
'provider:network_type': 'vxlan',
'provider:physical_network': None,
'provider:segmentation_id': 1234,
'router:external': False,
'shared': False,
'status': 'ACTIVE',
'subnets': ['fake subnet id',
'fake subnet id 2'],
}
fake_share_network = {
'id': 'fake nw info id',
'neutron_subnet_id': 'fake subnet id',
@ -96,12 +116,18 @@ class NeutronNetworkPluginTest(test.TestCase):
def setUp(self):
super(NeutronNetworkPluginTest, self).setUp()
self.plugin = plugin.NeutronNetworkPlugin()
self.plugin = self._get_neutron_network_plugin_instance()
self.plugin.db = db_api
self.fake_context = context.RequestContext(user_id='fake user',
project_id='fake project',
is_admin=False)
def _get_neutron_network_plugin_instance(self, config_data=None):
if config_data is None:
return plugin.NeutronNetworkPlugin()
with test_utils.create_temp_config_with_opts(config_data):
return plugin.NeutronNetworkPlugin()
@mock.patch.object(db_api, 'network_allocation_create',
mock.Mock(return_values=fake_network_allocation))
@mock.patch.object(db_api, 'share_network_get',
@ -394,23 +420,25 @@ class NeutronSingleNetworkPluginTest(test.TestCase):
plugin.NeutronSingleNetworkPlugin)
neutron_api.API.get_network.assert_called_once_with(fake_net_id)
def _get_neutron_single_network_plugin_instance(self):
fake_subnet_id = 'fake_subnet_id'
config_data = {
'DEFAULT': {
'neutron_net_id': 'fake_net_id',
'neutron_subnet_id': fake_subnet_id,
def _get_neutron_network_plugin_instance(self, config_data=None):
if not config_data:
fake_subnet_id = 'fake_subnet_id'
config_data = {
'DEFAULT': {
'neutron_net_id': 'fake_net_id',
'neutron_subnet_id': fake_subnet_id,
}
}
}
fake_net = {'subnets': [fake_subnet_id]}
self.mock_object(
neutron_api.API, 'get_network', mock.Mock(return_value=fake_net))
fake_net = {'subnets': [fake_subnet_id]}
self.mock_object(
neutron_api.API, 'get_network',
mock.Mock(return_value=fake_net))
with test_utils.create_temp_config_with_opts(config_data):
instance = plugin.NeutronSingleNetworkPlugin()
return instance
def test___update_share_network_net_data_same_values(self):
instance = self._get_neutron_single_network_plugin_instance()
instance = self._get_neutron_network_plugin_instance()
share_network = {
'neutron_net_id': instance.net,
'neutron_subnet_id': instance.subnet,
@ -422,7 +450,7 @@ class NeutronSingleNetworkPluginTest(test.TestCase):
self.assertEqual(share_network, result)
def test___update_share_network_net_data_different_values_empty(self):
instance = self._get_neutron_single_network_plugin_instance()
instance = self._get_neutron_network_plugin_instance()
share_network_input = {
'id': 'fake_share_network_id',
}
@ -445,7 +473,7 @@ class NeutronSingleNetworkPluginTest(test.TestCase):
{'n': 'foo', 's': 'fake_subnet_id'})
@ddt.unpack
def test___update_share_network_net_data_different_values(self, n, s):
instance = self._get_neutron_single_network_plugin_instance()
instance = self._get_neutron_network_plugin_instance()
share_network = {
'id': 'fake_share_network_id',
'neutron_net_id': n,
@ -462,7 +490,7 @@ class NeutronSingleNetworkPluginTest(test.TestCase):
self.assertFalse(instance.db.share_network_update.called)
def test___update_share_network_net_data_nova_net_id_present(self):
instance = self._get_neutron_single_network_plugin_instance()
instance = self._get_neutron_network_plugin_instance()
share_network = {
'id': 'fake_share_network_id',
'nova_net_id': 'foo',
@ -477,10 +505,11 @@ class NeutronSingleNetworkPluginTest(test.TestCase):
self.context, share_network)
self.assertFalse(instance.db.share_network_update.called)
@mock.patch.object(
plugin.NeutronNetworkPlugin, "allocate_network", mock.Mock())
def test_allocate_network(self):
instance = self._get_neutron_single_network_plugin_instance()
self.mock_object(plugin.NeutronNetworkPlugin, 'allocate_network')
plugin.NeutronNetworkPlugin.allocate_network.return_value = [
fake_neutron_port, fake_neutron_port]
instance = self._get_neutron_network_plugin_instance()
share_server = 'fake_share_server'
share_network = 'fake_share_network'
share_network_upd = 'updated_fake_share_network'
@ -499,7 +528,6 @@ class NeutronSingleNetworkPluginTest(test.TestCase):
plugin.NeutronNetworkPlugin.allocate_network.assert_called_once_with(
self.context, share_server, share_network_upd, count=count,
device_owner=device_owner)
plugin.NeutronNetworkPlugin.allocate_network.reset_mock()
@ddt.ddt
@ -512,10 +540,16 @@ class NeutronBindNetworkPluginTest(test.TestCase):
self.has_binding_ext_mock = self.mock_object(
neutron_api.API, '_has_port_binding_extension')
self.has_binding_ext_mock.return_value = True
self.bind_plugin = plugin.NeutronBindNetworkPlugin()
self.bind_plugin = self._get_neutron_network_plugin_instance()
self.bind_plugin.db = db_api
self.sleep_mock = self.mock_object(time, 'sleep')
def _get_neutron_network_plugin_instance(self, config_data=None):
if config_data is None:
return plugin.NeutronBindNetworkPlugin()
with test_utils.create_temp_config_with_opts(config_data):
return plugin.NeutronBindNetworkPlugin()
def test_wait_for_bind(self):
self.mock_object(self.bind_plugin.neutron_api, 'show_port')
self.bind_plugin.neutron_api.show_port.return_value = fake_neutron_port
@ -607,6 +641,160 @@ class NeutronBindNetworkPluginTest(test.TestCase):
self.bind_plugin._wait_for_ports_bind.assert_called_once_with(
[db_api.network_allocation_create()], fake_share_server)
@ddt.data({
'neutron_binding_profiles': None,
'binding_profiles': {}
}, {
'neutron_binding_profiles': 'fake_profile',
'binding_profiles': {}
}, {
'neutron_binding_profiles': 'fake_profile',
'binding_profiles': None
}, {
'neutron_binding_profiles': 'fake_profile',
'binding_profiles': {
'fake_profile': {
'neutron_switch_id': 'fake switch id',
'neutron_port_id': 'fake port id',
'neutron_switch_info': 'switch_ip: 127.0.0.1'
}
}
}, {
'neutron_binding_profiles': None,
'binding_profiles': {
'fake_profile': {
'neutron_switch_id': 'fake switch id',
'neutron_port_id': 'fake port id',
'neutron_switch_info': 'switch_ip: 127.0.0.1'
}
}
}, {
'neutron_binding_profiles': 'fake_profile_one,fake_profile_two',
'binding_profiles': {
'fake_profile_one': {
'neutron_switch_id': 'fake switch id 1',
'neutron_port_id': 'fake port id 1',
'neutron_switch_info': 'switch_ip: 127.0.0.1'
},
'fake_profile_two': {
'neutron_switch_id': 'fake switch id 2',
'neutron_port_id': 'fake port id 2',
'neutron_switch_info': 'switch_ip: 127.0.0.2'
}
}
}, {
'neutron_binding_profiles': 'fake_profile_two',
'binding_profiles': {
'fake_profile_one': {
'neutron_switch_id': 'fake switch id 1',
'neutron_port_id': 'fake port id 1',
'neutron_switch_info': 'switch_ip: 127.0.0.1'
},
'fake_profile_two': {
'neutron_switch_id': 'fake switch id 2',
'neutron_port_id': 'fake port id 2',
'neutron_switch_info': 'switch_ip: 127.0.0.2'
}
}
})
@ddt.unpack
@mock.patch.object(db_api, 'share_network_get',
mock.Mock(return_value=fake_share_network))
@mock.patch.object(db_api, 'share_server_get',
mock.Mock(return_value=fake_share_server))
def test__get_port_create_args(self, neutron_binding_profiles,
binding_profiles):
fake_device_owner = 'share'
fake_host_id = 'fake host'
neutron_host_id_opts = plugin.neutron_bind_network_plugin_opts[1]
self.mock_object(neutron_host_id_opts, 'default')
neutron_host_id_opts.default = fake_host_id
config_data = {
'DEFAULT': {
'neutron_net_id': fake_neutron_network['id'],
'neutron_subnet_id': fake_neutron_network['subnets'][0]
}
}
# Simulate absence of set values
if neutron_binding_profiles:
config_data['DEFAULT'][
'neutron_binding_profiles'] = neutron_binding_profiles
if binding_profiles:
for name, binding_profile in binding_profiles.items():
config_data[name] = binding_profile
instance = self._get_neutron_network_plugin_instance(config_data)
create_args = instance._get_port_create_args(fake_share_server,
fake_share_network,
fake_device_owner)
expected_create_args = {
'binding:vnic_type': 'baremetal',
'host_id': fake_host_id,
'network_id': fake_share_network['neutron_net_id'],
'subnet_id': fake_share_network['neutron_subnet_id'],
'device_owner': 'manila:' + fake_device_owner,
'device_id': fake_share_server['id']
}
if neutron_binding_profiles:
expected_create_args['binding:profile'] = {
'local_link_information': []
}
local_links = expected_create_args[
'binding:profile']['local_link_information']
for profile in neutron_binding_profiles.split(','):
if binding_profiles is None:
binding_profile = {}
else:
binding_profile = binding_profiles.get(profile, {})
local_links.append({
'port_id': binding_profile.get('neutron_port_id', None),
'switch_id': binding_profile.get('neutron_switch_id', None)
})
switch_info = binding_profile.get('neutron_switch_info', None)
if switch_info is None:
local_links[-1]['switch_info'] = None
else:
local_links[-1]['switch_info'] = cfg.types.Dict()(
switch_info)
self.assertEqual(expected_create_args, create_args)
@mock.patch.object(db_api, 'share_network_get',
mock.Mock(return_value=fake_share_network))
@mock.patch.object(db_api, 'share_server_get',
mock.Mock(return_value=fake_share_server))
def test__get_port_create_args_host_id(self):
fake_device_owner = 'share'
fake_host_id = 'fake host'
config_data = {
'DEFAULT': {
'neutron_net_id': fake_neutron_network['id'],
'neutron_subnet_id': fake_neutron_network['subnets'][0],
'neutron_host_id': fake_host_id
}
}
instance = self._get_neutron_network_plugin_instance(config_data)
create_args = instance._get_port_create_args(fake_share_server,
fake_share_network,
fake_device_owner)
expected_create_args = {
'binding:vnic_type': 'baremetal',
'host_id': fake_host_id,
'network_id': fake_share_network['neutron_net_id'],
'subnet_id': fake_share_network['neutron_subnet_id'],
'device_owner': 'manila:' + fake_device_owner,
'device_id': fake_share_server['id']
}
self.assertEqual(expected_create_args, create_args)
@ddt.ddt
class NeutronBindSingleNetworkPluginTest(test.TestCase):
@ -622,21 +810,52 @@ class NeutronBindSingleNetworkPluginTest(test.TestCase):
self.bind_plugin = plugin.NeutronBindNetworkPlugin()
self.bind_plugin.db = db_api
self.sleep_mock = self.mock_object(time, 'sleep')
fake_net_id = 'fake net id'
fake_subnet_id = 'fake subnet id'
config_data = {
'DEFAULT': {
'neutron_net_id': fake_net_id,
'neutron_subnet_id': fake_subnet_id,
}
}
fake_net = {'subnets': ['fake1', 'fake2', fake_subnet_id]}
self.mock_object(
neutron_api.API, 'get_network', mock.Mock(return_value=fake_net))
self.bind_plugin = self._get_neutron_network_plugin_instance()
self.bind_plugin.db = db_api
def _get_neutron_network_plugin_instance(self, config_data=None):
if not config_data:
fake_net_id = 'fake net id'
fake_subnet_id = 'fake subnet id'
config_data = {
'DEFAULT': {
'neutron_net_id': fake_net_id,
'neutron_subnet_id': fake_subnet_id,
}
}
fake_net = {'subnets': ['fake1', 'fake2', fake_subnet_id]}
self.mock_object(
neutron_api.API, 'get_network',
mock.Mock(return_value=fake_net))
with test_utils.create_temp_config_with_opts(config_data):
self.bind_plugin = plugin.NeutronBindSingleNetworkPlugin()
self.bind_plugin.db = db_api
return plugin.NeutronBindSingleNetworkPlugin()
def test_allocate_network(self):
self.mock_object(plugin.NeutronNetworkPlugin, 'allocate_network')
plugin.NeutronNetworkPlugin.allocate_network.return_value = [
'port1', 'port2']
instance = self._get_neutron_network_plugin_instance()
share_server = 'fake_share_server'
share_network = 'fake_share_network'
share_network_upd = 'updated_fake_share_network'
count = 2
device_owner = 'fake_device_owner'
self.mock_object(
instance, '_update_share_network_net_data',
mock.Mock(return_value=share_network_upd))
self.mock_object(instance, '_wait_for_ports_bind', mock.Mock())
instance.allocate_network(
self.context, share_server, share_network, count=count,
device_owner=device_owner)
instance._update_share_network_net_data.assert_called_once_with(
self.context, share_network)
plugin.NeutronNetworkPlugin.allocate_network.assert_called_once_with(
self.context, share_server, share_network_upd, count=count,
device_owner=device_owner)
instance._wait_for_ports_bind.assert_called_once_with(
['port1', 'port2'], share_server)
def test_init_valid(self):
fake_net_id = 'fake_net_id'
@ -778,30 +997,6 @@ class NeutronBindSingleNetworkPluginTest(test.TestCase):
self.context, share_network)
self.assertFalse(instance.db.share_network_update.called)
@mock.patch.object(
plugin.NeutronNetworkPlugin, "allocate_network", mock.Mock())
def test_allocate_network(self):
instance = self._get_neutron_single_network_plugin_instance()
share_server = 'fake_share_server'
share_network = 'fake_share_network'
share_network_upd = 'updated_fake_share_network'
count = 2
device_owner = 'fake_device_owner'
self.mock_object(
instance, '_update_share_network_net_data',
mock.Mock(return_value=share_network_upd))
instance.allocate_network(
self.context, share_server, share_network, count=count,
device_owner=device_owner)
instance._update_share_network_net_data.assert_called_once_with(
self.context, share_network)
plugin.NeutronNetworkPlugin.allocate_network.assert_called_once_with(
self.context, share_server, share_network_upd, count=count,
device_owner=device_owner)
plugin.NeutronNetworkPlugin.allocate_network.reset_mock()
def test_wait_for_bind(self):
self.mock_object(self.bind_plugin.neutron_api, 'show_port')
self.bind_plugin.neutron_api.show_port.return_value = fake_neutron_port
@ -893,6 +1088,160 @@ class NeutronBindSingleNetworkPluginTest(test.TestCase):
self.bind_plugin._wait_for_ports_bind.assert_called_once_with(
[db_api.network_allocation_create()], fake_share_server)
@ddt.data({
'neutron_binding_profiles': None,
'binding_profiles': {}
}, {
'neutron_binding_profiles': 'fake_profile',
'binding_profiles': {}
}, {
'neutron_binding_profiles': 'fake_profile',
'binding_profiles': None
}, {
'neutron_binding_profiles': 'fake_profile',
'binding_profiles': {
'fake_profile': {
'neutron_switch_id': 'fake switch id',
'neutron_port_id': 'fake port id',
'neutron_switch_info': 'switch_ip: 127.0.0.1'
}
}
}, {
'neutron_binding_profiles': None,
'binding_profiles': {
'fake_profile': {
'neutron_switch_id': 'fake switch id',
'neutron_port_id': 'fake port id',
'neutron_switch_info': 'switch_ip: 127.0.0.1'
}
}
}, {
'neutron_binding_profiles': 'fake_profile_one,fake_profile_two',
'binding_profiles': {
'fake_profile_one': {
'neutron_switch_id': 'fake switch id 1',
'neutron_port_id': 'fake port id 1',
'neutron_switch_info': 'switch_ip: 127.0.0.1'
},
'fake_profile_two': {
'neutron_switch_id': 'fake switch id 2',
'neutron_port_id': 'fake port id 2',
'neutron_switch_info': 'switch_ip: 127.0.0.2'
}
}
}, {
'neutron_binding_profiles': 'fake_profile_two',
'binding_profiles': {
'fake_profile_one': {
'neutron_switch_id': 'fake switch id 1',
'neutron_port_id': 'fake port id 1',
'neutron_switch_info': 'switch_ip: 127.0.0.1'
},
'fake_profile_two': {
'neutron_switch_id': 'fake switch id 2',
'neutron_port_id': 'fake port id 2',
'neutron_switch_info': 'switch_ip: 127.0.0.2'
}
}
})
@ddt.unpack
@mock.patch.object(db_api, 'share_network_get',
mock.Mock(return_value=fake_share_network))
@mock.patch.object(db_api, 'share_server_get',
mock.Mock(return_value=fake_share_server))
def test__get_port_create_args(self, neutron_binding_profiles,
binding_profiles):
fake_device_owner = 'share'
fake_host_id = 'fake host'
neutron_host_id_opts = plugin.neutron_bind_network_plugin_opts[1]
self.mock_object(neutron_host_id_opts, 'default')
neutron_host_id_opts.default = fake_host_id
config_data = {
'DEFAULT': {
'neutron_net_id': fake_neutron_network['id'],
'neutron_subnet_id': fake_neutron_network['subnets'][0]
}
}
# Simulate absence of set values
if neutron_binding_profiles:
config_data['DEFAULT'][
'neutron_binding_profiles'] = neutron_binding_profiles
if binding_profiles:
for name, binding_profile in binding_profiles.items():
config_data[name] = binding_profile
instance = self._get_neutron_network_plugin_instance(config_data)
create_args = instance._get_port_create_args(fake_share_server,
fake_share_network,
fake_device_owner)
expected_create_args = {
'binding:vnic_type': 'baremetal',
'host_id': fake_host_id,
'network_id': fake_share_network['neutron_net_id'],
'subnet_id': fake_share_network['neutron_subnet_id'],
'device_owner': 'manila:' + fake_device_owner,
'device_id': fake_share_server['id']
}
if neutron_binding_profiles:
expected_create_args['binding:profile'] = {
'local_link_information': []
}
local_links = expected_create_args[
'binding:profile']['local_link_information']
for profile in neutron_binding_profiles.split(','):
if binding_profiles is None:
binding_profile = {}
else:
binding_profile = binding_profiles.get(profile, {})
local_links.append({
'port_id': binding_profile.get('neutron_port_id', None),
'switch_id': binding_profile.get('neutron_switch_id', None)
})
switch_info = binding_profile.get('neutron_switch_info', None)
if switch_info is None:
local_links[-1]['switch_info'] = None
else:
local_links[-1]['switch_info'] = cfg.types.Dict()(
switch_info)
self.assertEqual(expected_create_args, create_args)
@mock.patch.object(db_api, 'share_network_get',
mock.Mock(return_value=fake_share_network))
@mock.patch.object(db_api, 'share_server_get',
mock.Mock(return_value=fake_share_server))
def test__get_port_create_args_host_id(self):
fake_device_owner = 'share'
fake_host_id = 'fake host'
config_data = {
'DEFAULT': {
'neutron_net_id': fake_neutron_network['id'],
'neutron_subnet_id': fake_neutron_network['subnets'][0],
'neutron_host_id': fake_host_id
}
}
instance = self._get_neutron_network_plugin_instance(config_data)
create_args = instance._get_port_create_args(fake_share_server,
fake_share_network,
fake_device_owner)
expected_create_args = {
'binding:vnic_type': 'baremetal',
'host_id': fake_host_id,
'network_id': fake_share_network['neutron_net_id'],
'subnet_id': fake_share_network['neutron_subnet_id'],
'device_owner': 'manila:' + fake_device_owner,
'device_id': fake_share_server['id']
}
self.assertEqual(expected_create_args, create_args)
class NeutronBindNetworkPluginWithNormalTypeTest(test.TestCase):
def setUp(self):