Merge "Add MTU information in DB and API"

This commit is contained in:
Jenkins 2016-08-13 01:47:21 +00:00 committed by Gerrit Code Review
commit a3087b309a
16 changed files with 333 additions and 21 deletions

View File

@ -71,6 +71,7 @@ REST_API_VERSION_HISTORY = """
* 2.18 - Add gateway to the JSON response of share network show API.
* 2.19 - Share snapshot instances admin APIs
(list/show/detail/reset-status).
* 2.20 - Add MTU to the JSON response of share network show API.
"""
@ -78,7 +79,7 @@ REST_API_VERSION_HISTORY = """
# The default api version request is defined to be the
# the minimum version of the API supported.
_MIN_API_VERSION = "2.0"
_MAX_API_VERSION = "2.19"
_MAX_API_VERSION = "2.20"
DEFAULT_API_VERSION = _MIN_API_VERSION

View File

@ -122,3 +122,7 @@ user documentation.
2.19
----
Add admin APIs(list/show/detail/reset-status) of snapshot instances.
2.20
----
Add MTU in share network show API.

View File

@ -20,7 +20,7 @@ class ViewBuilder(common.ViewBuilder):
"""Model a server API response as a python dictionary."""
_collection_name = 'share_networks'
_detail_version_modifiers = ["add_gateway"]
_detail_version_modifiers = ["add_gateway", "add_mtu"]
def build_share_network(self, request, share_network):
"""View of a share network."""
@ -61,3 +61,7 @@ class ViewBuilder(common.ViewBuilder):
@common.ViewBuilder.versioned_method("2.18")
def add_gateway(self, context, network_dict, network):
network_dict['gateway'] = network.get('gateway')
@common.ViewBuilder.versioned_method("2.20")
def add_mtu(self, context, network_dict, network):
network_dict['mtu'] = network.get('mtu')

View File

@ -0,0 +1,40 @@
# 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.
"""add_mtu_network_allocations
Revision ID: 493eaffd79e1
Revises: e8ea58723178
Create Date: 2016-08-01 14:18:31.899606
"""
# revision identifiers, used by Alembic.
revision = '493eaffd79e1'
down_revision = 'e8ea58723178'
from alembic import op
import sqlalchemy as sa
def upgrade():
op.add_column(
'network_allocations',
sa.Column('mtu', sa.Integer, nullable=True))
op.add_column(
'share_networks',
sa.Column('mtu', sa.Integer, nullable=True))
def downgrade():
op.drop_column('network_allocations', 'mtu')
op.drop_column('share_networks', 'mtu')

View File

@ -755,6 +755,7 @@ class ShareNetwork(BASE, ManilaBase):
segmentation_id = Column(Integer, nullable=True)
cidr = Column(String(64), nullable=True)
gateway = Column(String(64), nullable=True)
mtu = Column(Integer, nullable=True)
ip_version = Column(Integer, nullable=True)
name = Column(String(255), nullable=True)
description = Column(String(255), nullable=True)
@ -864,6 +865,7 @@ class NetworkAllocation(BASE, ManilaBase):
ip_version = Column(Integer, nullable=True)
cidr = Column(String(64), nullable=True)
gateway = Column(String(64), nullable=True)
mtu = Column(Integer, nullable=True)
network_type = Column(String(32), nullable=True)
segmentation_id = Column(Integer, nullable=True)
mac_address = Column(String(32), nullable=True)

View File

@ -131,6 +131,7 @@ class NeutronNetworkPlugin(network.NetworkBaseAPI):
'segmentation_id': share_network['segmentation_id'],
'ip_version': share_network['ip_version'],
'cidr': share_network['cidr'],
'mtu': share_network['mtu'],
}
return self.db.network_allocation_create(context, port_dict)
@ -154,7 +155,8 @@ class NeutronNetworkPlugin(network.NetworkBaseAPI):
provider_nw_dict = {
'network_type': net_info['provider:network_type'],
'segmentation_id': net_info['provider:segmentation_id']
'segmentation_id': net_info['provider:segmentation_id'],
'mtu': net_info['mtu'],
}
share_network.update(provider_nw_dict)

View File

@ -92,6 +92,7 @@ class NovaNetworkPlugin(network.NetworkBaseAPI):
'ip_version': share_network['ip_version'],
'segmentation_id': share_network['segmentation_id'],
'network_type': share_network['network_type'],
'mtu': share_network['mtu'],
}
self.nova_api.fixed_ip_reserve(self.admin_context, ip_address)
allocations.append(
@ -155,6 +156,7 @@ class NovaNetworkPlugin(network.NetworkBaseAPI):
'ip_version': (4 if nova_net['cidr'] else 6),
'segmentation_id': nova_net['vlan'],
'network_type': ('vlan' if nova_net['vlan'] else 'flat'),
'mtu': nova_net['mtu'],
}
share_network.update(data)
if self.label != 'admin':

View File

@ -65,6 +65,12 @@ standalone_network_plugin_opts = [
help="IP version of network. Optional."
"Allowed values are '4' and '6'. Default value is '4'.",
deprecated_group='DEFAULT'),
cfg.IntOpt(
'standalone_network_plugin_mtu',
default=1500,
help="Maximum Transmission Unit (MTU) value of the network. Default "
"value is 1500.",
deprecated_group='DEFAULT'),
]
CONF = cfg.CONF
@ -135,6 +141,7 @@ class StandaloneNetworkPlugin(network.NetworkBaseAPI):
six.text_type(self.net.network),
self.gateway,
six.text_type(self.net.broadcast))
self.mtu = self.configuration.standalone_network_plugin_mtu
def _get_network(self):
"""Returns IPNetwork object calculated from gateway and netmask."""
@ -251,6 +258,7 @@ class StandaloneNetworkPlugin(network.NetworkBaseAPI):
'cidr': six.text_type(self.net.cidr),
'gateway': six.text_type(self.gateway),
'ip_version': self.ip_version,
'mtu': self.mtu,
}
share_network.update(data)
if self.label != 'admin':
@ -284,6 +292,7 @@ class StandaloneNetworkPlugin(network.NetworkBaseAPI):
'cidr': share_network['cidr'],
'gateway': share_network['gateway'],
'ip_version': share_network['ip_version'],
'mtu': share_network['mtu'],
}
allocations.append(
self.db.network_allocation_create(context, data))

View File

@ -26,7 +26,6 @@ class ViewBuilderTestCase(test.TestCase):
def setUp(self):
super(ViewBuilderTestCase, self).setUp()
self.builder = share_networks.ViewBuilder()
self.req = fakes.HTTPRequest.blank('/share-networks', version="2.18")
def test__collection_name(self):
self.assertEqual('share_networks', self.builder._collection_name)
@ -36,13 +35,14 @@ class ViewBuilderTestCase(test.TestCase):
{'id': 'fake_sn_id', 'name': 'fake_sn_name', 'fake_extra_key': 'foo'},
)
def test_build_share_network_v_2_18(self, sn):
req = fakes.HTTPRequest.blank('/share-networks', version="2.18")
expected_keys = (
'id', 'name', 'project_id', 'created_at', 'updated_at',
'neutron_net_id', 'neutron_subnet_id', 'nova_net_id',
'network_type', 'segmentation_id', 'cidr', 'ip_version',
'gateway', 'description')
result = self.builder.build_share_network(self.req, sn)
result = self.builder.build_share_network(req, sn)
self.assertEqual(1, len(result))
self.assertIn('share_network', result)
@ -71,6 +71,7 @@ class ViewBuilderTestCase(test.TestCase):
dict(id='fake_id2', name='fake_name2')],
)
def test_build_share_networks_with_details_v_2_18(self, share_networks):
req = fakes.HTTPRequest.blank('/share-networks', version="2.18")
expected = []
for share_network in share_networks:
expected.append(dict(
@ -91,7 +92,7 @@ class ViewBuilderTestCase(test.TestCase):
expected = {'share_networks': expected}
result = self.builder.build_share_networks(
self.req, share_networks, True)
req, share_networks, True)
self.assertEqual(expected, result)
@ -104,6 +105,7 @@ class ViewBuilderTestCase(test.TestCase):
)
def test_build_share_networks_without_details_v_2_18(self,
share_networks):
req = fakes.HTTPRequest.blank('/share-networks', version="2.18")
expected = []
for share_network in share_networks:
expected.append(dict(
@ -111,6 +113,104 @@ class ViewBuilderTestCase(test.TestCase):
expected = {'share_networks': expected}
result = self.builder.build_share_networks(
self.req, share_networks, False)
req, share_networks, False)
self.assertEqual(expected, result)
@ddt.data(
{'id': 'fake_sn_id', 'name': 'fake_sn_name'},
{'id': 'fake_sn_id', 'name': 'fake_sn_name', 'fake_extra_key': 'foo'},
)
def test_build_share_network_v_2_20(self, sn):
req = fakes.HTTPRequest.blank('/share-networks', version="2.20")
expected_keys = (
'id', 'name', 'project_id', 'created_at', 'updated_at',
'neutron_net_id', 'neutron_subnet_id', 'nova_net_id',
'network_type', 'segmentation_id', 'cidr', 'ip_version',
'gateway', 'description', 'mtu')
result = self.builder.build_share_network(req, sn)
self.assertEqual(1, len(result))
self.assertIn('share_network', result)
self.assertEqual(sn['id'], result['share_network']['id'])
self.assertEqual(sn['name'], result['share_network']['name'])
self.assertEqual(len(expected_keys), len(result['share_network']))
for key in expected_keys:
self.assertIn(key, result['share_network'])
for key in result['share_network']:
self.assertIn(key, expected_keys)
@ddt.data(
[], [{
'id': 'fake_id',
'name': 'fake_name',
'project_id': 'fake_project_id',
'created_at': 'fake_created_at',
'updated_at': 'fake_updated_at',
'neutron_net_id': 'fake_neutron_net_id',
'neutron_subnet_id': 'fake_neutron_subnet_id',
'nova_net_id': 'fake_nova_net_id',
'network_type': 'fake_network_type',
'segmentation_id': 'fake_segmentation_id',
'cidr': 'fake_cidr',
'ip_version': 'fake_ip_version',
'gateway': 'fake_gateway',
'description': 'fake_description',
'mtu': 1509
},
{
'id': 'fake_id2',
'name': 'fake_name2'
}],
)
def test_build_share_networks_with_details_v_2_20(self, share_networks):
req = fakes.HTTPRequest.blank('/share-networks', version="2.20")
expected = []
for share_network in share_networks:
expected.append({
'id': share_network.get('id'),
'name': share_network.get('name'),
'project_id': share_network.get('project_id'),
'created_at': share_network.get('created_at'),
'updated_at': share_network.get('updated_at'),
'neutron_net_id': share_network.get('neutron_net_id'),
'neutron_subnet_id': share_network.get('neutron_subnet_id'),
'nova_net_id': share_network.get('nova_net_id'),
'network_type': share_network.get('network_type'),
'segmentation_id': share_network.get('segmentation_id'),
'cidr': share_network.get('cidr'),
'ip_version': share_network.get('ip_version'),
'gateway': share_network.get('gateway'),
'description': share_network.get('description'),
'mtu': share_network.get('mtu'),
})
expected = {'share_networks': expected}
result = self.builder.build_share_networks(
req, share_networks, True)
self.assertEqual(expected, result)
@ddt.data(
[],
[{'id': 'foo', 'name': 'bar'}],
[{'id': 'id1', 'name': 'name1'}, {'id': 'id2', 'name': 'name2'}],
[{'id': 'id1', 'name': 'name1'},
{'id': 'id2', 'name': 'name2', 'fake': 'I should not be returned'}],
)
def test_build_share_networks_without_details_v_2_20(self,
share_networks):
req = fakes.HTTPRequest.blank('/share-networks', version="2.20")
expected = []
for share_network in share_networks:
expected.append({
'id': share_network.get('id'),
'name': share_network.get('name')
})
expected = {'share_networks': expected}
result = self.builder.build_share_networks(
req, share_networks, False)
self.assertEqual(expected, result)

View File

@ -793,3 +793,130 @@ class RemoveHostFromDriverPrivateDataChecks(BaseMigrationChecks):
for row in rows:
self.test_case.assertTrue(hasattr(row, self.host_column_name))
self.test_case.assertEqual('unknown', row[self.host_column_name])
@map_to_migration('493eaffd79e1')
class NewMTUColumnChecks(BaseMigrationChecks):
na_table_name = 'network_allocations'
sn_table_name = 'share_networks'
na_ids = ['network_allocation_id_fake_3_%d' % i for i in (1, 2, 3)]
sn_ids = ['share_network_id_fake_3_%d' % i for i in (1, 2)]
def setup_upgrade_data(self, engine):
user_id = 'user_id'
project_id = 'project_id'
share_server_id = 'share_server_id_foo_2'
# Create share network
share_network_data = {
'id': self.sn_ids[0],
'user_id': user_id,
'project_id': project_id,
}
sn_table = utils.load_table(self.sn_table_name, engine)
engine.execute(sn_table.insert(share_network_data))
# Create share server
share_server_data = {
'id': share_server_id,
'share_network_id': share_network_data['id'],
'host': 'fake_host',
'status': 'active',
}
ss_table = utils.load_table('share_servers', engine)
engine.execute(ss_table.insert(share_server_data))
# Create network allocations
network_allocations = [
{
'id': self.na_ids[0],
'share_server_id': share_server_id,
'ip_address': '1.1.1.1',
},
{
'id': self.na_ids[1],
'share_server_id': share_server_id,
'ip_address': '2.2.2.2',
},
]
na_table = utils.load_table(self.na_table_name, engine)
engine.execute(na_table.insert(network_allocations))
def check_upgrade(self, engine, data):
na_table = utils.load_table(self.na_table_name, engine)
for na in engine.execute(na_table.select()):
self.test_case.assertTrue(hasattr(na, 'mtu'))
# Create network allocation
network_allocations = [
{
'id': self.na_ids[2],
'share_server_id': na.share_server_id,
'ip_address': '3.3.3.3',
'gateway': '3.3.3.1',
'network_type': 'vlan',
'segmentation_id': 1005,
'ip_version': 4,
'cidr': '240.0.0.0/16',
'mtu': 1509,
},
]
engine.execute(na_table.insert(network_allocations))
# Select network allocations with mtu info
for na in engine.execute(
na_table.select().where(na_table.c.mtu == '1509')):
self.test_case.assertTrue(hasattr(na, 'mtu'))
self.test_case.assertEqual(network_allocations[0]['mtu'],
getattr(na, 'mtu'))
# Select all entries and check for the value
for na in engine.execute(na_table.select()):
self.test_case.assertTrue(hasattr(na, 'mtu'))
if na['id'] == self.na_ids[2]:
self.test_case.assertEqual(network_allocations[0]['mtu'],
getattr(na, 'mtu'))
else:
self.test_case.assertIsNone(na['mtu'])
sn_table = utils.load_table(self.sn_table_name, engine)
for sn in engine.execute(sn_table.select()):
self.test_case.assertTrue(hasattr(sn, 'mtu'))
# Create share network
share_networks = [
{
'id': self.sn_ids[1],
'user_id': sn.user_id,
'project_id': sn.project_id,
'gateway': '1.1.1.1',
'name': 'name_foo_2',
'mtu': 1509,
},
]
engine.execute(sn_table.insert(share_networks))
# Select share network with MTU set
for sn in engine.execute(
sn_table.select().where(sn_table.c.name == 'name_foo_2')):
self.test_case.assertTrue(hasattr(sn, 'mtu'))
self.test_case.assertEqual(share_networks[0]['mtu'],
getattr(sn, 'mtu'))
# Select all entries and check for the value
for sn in engine.execute(sn_table.select()):
self.test_case.assertTrue(hasattr(sn, 'mtu'))
if sn['id'] == self.sn_ids[1]:
self.test_case.assertEqual(network_allocations[0]['mtu'],
getattr(sn, 'mtu'))
else:
self.test_case.assertIsNone(sn['mtu'])
def check_downgrade(self, engine):
for table_name, ids in ((self.na_table_name, self.na_ids),
(self.sn_table_name, self.sn_ids)):
table = utils.load_table(table_name, engine)
db_result = engine.execute(table.select())
self.test_case.assertTrue(db_result.rowcount >= len(ids))
for record in db_result:
self.test_case.assertFalse(hasattr(record, 'mtu'))

View File

@ -62,6 +62,7 @@ fake_share_network = {
'ip_version': 4,
'cidr': 'fake_cidr',
'gateway': 'fake_gateway',
'mtu': 1509,
}
fake_share_server = {
@ -84,6 +85,7 @@ fake_network_allocation = {
'ip_version': fake_share_network['ip_version'],
'cidr': fake_share_network['cidr'],
'gateway': fake_share_network['gateway'],
'mtu': 1509,
}
@ -252,10 +254,16 @@ class NeutronNetworkPluginTest(test.TestCase):
@mock.patch.object(db_api, 'share_network_update', mock.Mock())
def test_save_neutron_network_data(self):
neutron_nw_info = {'provider:network_type': 'vlan',
'provider:segmentation_id': 1000}
share_nw_update_dict = {'network_type': 'vlan',
'segmentation_id': 1000}
neutron_nw_info = {
'provider:network_type': 'vlan',
'provider:segmentation_id': 1000,
'mtu': 1509,
}
share_nw_update_dict = {
'network_type': 'vlan',
'segmentation_id': 1000,
'mtu': 1509,
}
with mock.patch.object(self.plugin.neutron_api,
'get_network',

View File

@ -61,7 +61,7 @@ class NovaNetworkPluginTest(test.TestCase):
gateway='20.0.0.1', gateway_v6=None,
dhcp_server='20.0.0.2', broadcast='20.0.0.255',
vpn_private_address='20.0.0.3', vpn_public_address='20.0.0.4',
dns1='20.0.0.5', dns2='20.0.0.6', vlan=None)
dns1='20.0.0.5', dns2='20.0.0.6', vlan=None, mtu=1509)
if net_type == 'vlan':
nova_net['vlan'] = 100
self.mock_object(self.instance.nova_api, 'fixed_ip_reserve')
@ -92,7 +92,7 @@ class NovaNetworkPluginTest(test.TestCase):
self.fake_context, share_network['id'],
dict(cidr=nova_net['cidr'], gateway=nova_net['gateway'],
ip_version=4, segmentation_id=nova_net['vlan'],
network_type=net_type))
network_type=net_type, mtu=1509))
self.instance.db.network_allocations_get_by_ip_address.\
assert_has_calls([
mock.call(self.fake_context, '20.0.0.7'),
@ -117,7 +117,7 @@ class NovaNetworkPluginTest(test.TestCase):
gateway='20.0.0.1', gateway_v6=None,
dhcp_server='20.0.0.254', broadcast='20.0.0.255',
vpn_private_address='20.0.0.3', vpn_public_address='20.0.0.4',
dns1='20.0.0.5', dns2='20.0.0.6', vlan=None)
dns1='20.0.0.5', dns2='20.0.0.6', vlan=None, mtu=1509)
if net_type == 'vlan':
nova_net['vlan'] = 100
self.mock_object(self.instance.nova_api, 'fixed_ip_reserve')
@ -152,7 +152,7 @@ class NovaNetworkPluginTest(test.TestCase):
self.fake_context, self.share_network['id'],
dict(cidr=nova_net['cidr'], gateway=nova_net['gateway'],
ip_version=4, segmentation_id=nova_net['vlan'],
network_type=net_type))
network_type=net_type, mtu=1509))
self.instance.db.network_allocations_get_by_ip_address.\
assert_has_calls([
mock.call(self.fake_context, '20.0.0.2'),
@ -170,7 +170,7 @@ class NovaNetworkPluginTest(test.TestCase):
gateway='20.0.0.1', gateway_v6=None,
dhcp_server='20.0.0.2', broadcast='20.0.0.255',
vpn_private_address='20.0.0.3', vpn_public_address='20.0.0.4',
dns1='20.0.0.5', dns2='20.0.0.6', vlan=100)
dns1='20.0.0.5', dns2='20.0.0.6', vlan=100, mtu=1509)
self.mock_object(
self.instance.nova_api, 'network_get',
mock.Mock(return_value=nova_net))
@ -190,7 +190,7 @@ class NovaNetworkPluginTest(test.TestCase):
self.fake_context, self.share_network['id'],
dict(cidr=nova_net['cidr'], gateway=nova_net['gateway'],
ip_version=4, segmentation_id=nova_net['vlan'],
network_type='vlan'))
network_type='vlan', mtu=1509))
self.assertEqual(
248,
self.instance.db.network_allocations_get_by_ip_address.call_count)

View File

@ -311,7 +311,8 @@ class StandaloneNetworkPluginTest(test.TestCase):
dict(network_type=None, segmentation_id=None,
cidr=six.text_type(instance.net.cidr),
gateway=six.text_type(instance.gateway),
ip_version=4))
ip_version=4,
mtu=1500))
def test_allocate_network_zero_addresses_ipv6(self):
data = {
@ -334,7 +335,8 @@ class StandaloneNetworkPluginTest(test.TestCase):
dict(network_type=None, segmentation_id=None,
cidr=six.text_type(instance.net.cidr),
gateway=six.text_type(instance.gateway),
ip_version=6))
ip_version=6,
mtu=1500))
def test_allocate_network_one_ip_address_ipv4_no_usages_exist(self):
data = {
@ -363,6 +365,7 @@ class StandaloneNetworkPluginTest(test.TestCase):
'cidr': '10.0.0.0/24',
'gateway': '10.0.0.1',
'ip_version': 4,
'mtu': 1500,
}
instance.db.share_network_update.assert_called_once_with(
fake_context, fake_share_network['id'], na_data)
@ -408,6 +411,7 @@ class StandaloneNetworkPluginTest(test.TestCase):
'cidr': six.text_type(instance.net.cidr),
'gateway': six.text_type(instance.gateway),
'ip_version': 4,
'mtu': 1500,
}
instance.db.share_network_update.assert_called_once_with(
ctxt, fake_share_network['id'], dict(**na_data))
@ -452,6 +456,7 @@ class StandaloneNetworkPluginTest(test.TestCase):
dict(network_type=None, segmentation_id=None,
cidr=six.text_type(instance.net.cidr),
gateway=six.text_type(instance.gateway),
ip_version=4))
ip_version=4,
mtu=1500))
instance.db.network_allocations_get_by_ip_address.assert_has_calls(
[mock.call(fake_context, '10.0.0.2')])

View File

@ -34,7 +34,7 @@ ShareGroup = [
help="The minimum api microversion is configured to be the "
"value of the minimum microversion supported by Manila."),
cfg.StrOpt("max_api_microversion",
default="2.19",
default="2.20",
help="The maximum api microversion is configured to be the "
"value of the latest microversion supported by Manila."),
cfg.StrOpt("region",

View File

@ -53,6 +53,10 @@ class ShareNetworkListMixin(object):
if utils.is_microversion_supported('2.18'):
keys.append('gateway')
# In v2.20 and beyond, we expect mtu.
if utils.is_microversion_supported('2.20'):
keys.append('mtu')
[self.assertIn(key, sn.keys()) for sn in listed for key in keys]
@test.attr(type=[base.TAG_POSITIVE, base.TAG_API])

View File

@ -0,0 +1,4 @@
---
features:
- Store network MTU value into DB to make it possible for drivers with share
server support to support different values than 1500.