Make type__ mandatory for bond creation

Added validation to bond creating for field 'bond_properties' and
bond_properties.type__. They are mandatory and bond can not be created
without type__.
Allowed modes for dpdkovs and ovs types:
   - active-backup
   - balance-slb'
   - balance-tcp
   - lacp-balance-tcp
Allowed modes for linux type:
   - active-backup
   - balance-rr
   - balance-xor
   - broadcast
   - 802.3ad
   - balance-tlb
   - balance-alb

Change-Id: Ic5a443a347b5abbf235e88bd95154b56a627b76f
Closes-Bug: #1566252
This commit is contained in:
ntymtsiv 2016-07-14 15:46:48 +03:00
parent e84303dc33
commit 205224d573
7 changed files with 240 additions and 54 deletions

View File

@ -878,18 +878,16 @@ class TestPublicNetworkAssigment(BaseIntegrationTest):
node1, macs1 = self.create_node_with_preset_macs(cluster,
['controller'],
3)
self.env.make_bond_via_api('ovsbond0',
consts.BOND_MODES.balance_tcp,
['eth1', 'eth2'],
node1['id'])
self.env.make_bond_via_api(
'ovsbond0', consts.BOND_MODES.balance_tcp, ['eth1', 'eth2'],
node1['id'], bond_properties={'type__': consts.BOND_TYPES.ovs})
node2, macs2 = self.create_node_with_preset_macs(cluster,
['cinder'],
3)
self.env.make_bond_via_api('ovsbond0',
consts.BOND_MODES.balance_tcp,
['eth1', 'eth2'],
node2['id'])
self.env.make_bond_via_api(
'ovsbond0', consts.BOND_MODES.balance_tcp, ['eth1', 'eth2'],
node2['id'], bond_properties={'type__': consts.BOND_TYPES.ovs})
self.check_network_assigments(node1, {
'eth0': self.default_networks,

View File

@ -23,6 +23,7 @@ from nailgun.consts import BOND_XMIT_HASH_POLICY
from nailgun.consts import HYPERVISORS
from nailgun.consts import NETWORK_INTERFACE_TYPES
from nailgun.db import db
from nailgun.extensions.network_manager.validators import network
from nailgun import objects
from nailgun.settings import settings
from nailgun.test.base import BaseIntegrationTest
@ -154,6 +155,7 @@ class TestNodeNICsBonding(BaseIntegrationTest):
def prepare_bond_w_props(self, bond_name='bond0',
bond_type=BOND_TYPES.linux,
bond_mode=BOND_MODES.l_802_3ad,
iface_props=None):
if iface_props is None:
iface_props = {}
@ -162,7 +164,7 @@ class TestNodeNICsBonding(BaseIntegrationTest):
"name": bond_name,
"type": NETWORK_INTERFACE_TYPES.bond,
"bond_properties": {
"mode": BOND_MODES.l_802_3ad,
"mode": bond_mode,
"xmit_hash_policy": BOND_XMIT_HASH_POLICY.layer2_3,
"lacp_rate": "slow",
"type__": bond_type
@ -245,7 +247,8 @@ class TestNodeNICsBonding(BaseIntegrationTest):
def test_nics_ovs_bond_create_failed_without_dpdk(self):
bond_name = 'bond0'
self.prepare_bond_w_props(bond_name=bond_name,
bond_type=BOND_TYPES.dpdkovs)
bond_type=BOND_TYPES.dpdkovs,
bond_mode=BOND_MODES.balance_tcp)
self.node_nics_put_check_error("Bond interface '{0}': DPDK should be"
" enabled for 'dpdkovs' bond type".
format(bond_name))
@ -273,6 +276,7 @@ class TestNodeNICsBonding(BaseIntegrationTest):
bond = [iface for iface in self.data
if iface['type'] == NETWORK_INTERFACE_TYPES.bond][0]
bond['bond_properties']['type__'] = BOND_TYPES.dpdkovs
bond['bond_properties']['mode'] = BOND_MODES.balance_tcp
self.node_nics_put_check_error(
"Bond interface '{0}': DPDK should be enabled for 'dpdkovs' bond"
" type".format(bond_name))
@ -364,6 +368,9 @@ class TestNodeNICsBonding(BaseIntegrationTest):
"name": 'ovs-bond0',
"type": NETWORK_INTERFACE_TYPES.bond,
"mode": "unknown",
"bond_properties": {
'type__': BOND_TYPES.linux
},
"slaves": [
{"name": self.other_nic["name"]},
{"name": self.empty_nic["name"]}],
@ -380,6 +387,9 @@ class TestNodeNICsBonding(BaseIntegrationTest):
self.data.append({
"name": 'ovs-bond0',
"type": NETWORK_INTERFACE_TYPES.bond,
"bond_properties": {
'type__': BOND_TYPES.linux
},
"slaves": [
{"name": self.other_nic["name"]},
{"name": self.empty_nic["name"]}],
@ -396,7 +406,8 @@ class TestNodeNICsBonding(BaseIntegrationTest):
"name": 'bond0',
"type": NETWORK_INTERFACE_TYPES.bond,
"bond_properties": {
"xmit_hash_policy": BOND_XMIT_HASH_POLICY.layer2_3
"xmit_hash_policy": BOND_XMIT_HASH_POLICY.layer2_3,
'type__': BOND_TYPES.linux
},
"slaves": [
{"name": self.other_nic["name"]},
@ -414,7 +425,8 @@ class TestNodeNICsBonding(BaseIntegrationTest):
"name": 'bond0',
"type": NETWORK_INTERFACE_TYPES.bond,
"bond_properties": {
"mode": 'unknown'
"mode": 'unknown',
'type__': BOND_TYPES.linux
},
"slaves": [
{"name": self.other_nic["name"]},
@ -433,6 +445,7 @@ class TestNodeNICsBonding(BaseIntegrationTest):
"type": NETWORK_INTERFACE_TYPES.bond,
"bond_properties": {
"mode": BOND_MODES.balance_xor,
'type__': BOND_TYPES.linux,
"policy": BOND_XMIT_HASH_POLICY.layer2_3
},
"slaves": [
@ -480,6 +493,9 @@ class TestNodeNICsBonding(BaseIntegrationTest):
self.data.append({
"name": 'ovs-bond0',
"type": NETWORK_INTERFACE_TYPES.bond,
"bond_properties": {
"type__": BOND_TYPES.ovs
},
"mode": BOND_MODES.balance_slb,
"slaves": [
{"name": self.other_nic["name"]},
@ -496,6 +512,9 @@ class TestNodeNICsBonding(BaseIntegrationTest):
self.data.append({
"name": 'ovs-bond0',
"type": NETWORK_INTERFACE_TYPES.bond,
"bond_properties": {
"type__": BOND_TYPES.ovs
},
"mode": BOND_MODES.balance_slb,
"slaves": [
{"name": self.other_nic["name"]},
@ -514,6 +533,9 @@ class TestNodeNICsBonding(BaseIntegrationTest):
"name": 'ovs-bond0',
"type": NETWORK_INTERFACE_TYPES.bond,
"mode": BOND_MODES.balance_slb,
"bond_properties": {
"type__": BOND_TYPES.ovs
},
"slaves": [
{"name": self.other_nic["name"]},
{"name": self.empty_nic["name"]}],
@ -533,6 +555,9 @@ class TestNodeNICsBonding(BaseIntegrationTest):
"name": 'ovs-bond0',
"type": NETWORK_INTERFACE_TYPES.bond,
"mode": BOND_MODES.balance_slb,
"bond_properties": {
"type__": BOND_TYPES.ovs
},
"slaves": [
{"name": self.other_nic["name"]},
{"name": "some_nic"}],
@ -549,6 +574,9 @@ class TestNodeNICsBonding(BaseIntegrationTest):
self.data.append({
"name": 'ovs-bond0',
"type": NETWORK_INTERFACE_TYPES.bond,
"bond_properties": {
"type__": BOND_TYPES.ovs
},
"mode": BOND_MODES.balance_slb,
"slaves": [
{"name": self.other_nic["name"]},
@ -566,6 +594,9 @@ class TestNodeNICsBonding(BaseIntegrationTest):
self.data.append({
"name": 'ovs-bond0',
"type": NETWORK_INTERFACE_TYPES.bond,
"bond_properties": {
"type__": BOND_TYPES.ovs
},
"mode": BOND_MODES.balance_slb,
"slaves": [
{"name": self.other_nic["name"]},
@ -587,6 +618,9 @@ class TestNodeNICsBonding(BaseIntegrationTest):
self.data.append({
"name": 'lnx-bond0',
"type": NETWORK_INTERFACE_TYPES.bond,
"bond_properties": {
"type__": BOND_TYPES.linux
},
"mode": mode,
"slaves": [
{"name": self.admin_nic["name"]},
@ -610,6 +644,9 @@ class TestNodeNICsBonding(BaseIntegrationTest):
self.data.append({
"name": 'ovs-bond0',
"type": NETWORK_INTERFACE_TYPES.bond,
"bond_properties": {
"type__": BOND_TYPES.ovs
},
"mode": mode,
"slaves": [
{"name": self.admin_nic["name"]},
@ -632,6 +669,9 @@ class TestNodeNICsBonding(BaseIntegrationTest):
self.data.append({
"name": 'ovs-bond0',
"type": NETWORK_INTERFACE_TYPES.bond,
"bond_properties": {
"type__": BOND_TYPES.ovs
},
"mode": mode,
"slaves": [
{"name": self.admin_nic["name"]},
@ -653,6 +693,9 @@ class TestNodeNICsBonding(BaseIntegrationTest):
self.data.append({
"name": 'ovs-bond0',
"type": NETWORK_INTERFACE_TYPES.bond,
"bond_properties": {
"type__": BOND_TYPES.ovs
},
"mode": mode,
"slaves": [
{"name": self.empty_nic["name"]},
@ -714,6 +757,9 @@ class TestNodeNICsBonding(BaseIntegrationTest):
self.data.append({
"name": 'ovs-bond0',
"type": NETWORK_INTERFACE_TYPES.bond,
"bond_properties": {
"type__": BOND_TYPES.ovs
},
"mode": BOND_MODES.balance_slb,
"slaves": [
{"name": self.admin_nic["name"]},
@ -734,3 +780,83 @@ class TestNodeNICsBonding(BaseIntegrationTest):
"enabled interface '{1}'".format(self.env.nodes[0]["id"],
self.sriov_nic['name'])
)
def test_nics_bond_create_failed_without_type__(self):
self.data.append({
"name": 'ovs-bond0',
"type": NETWORK_INTERFACE_TYPES.bond,
"bond_properties": {
"mode": BOND_MODES.balance_slb
},
"slaves": [
{"name": self.admin_nic["name"]},
{"name": self.sriov_nic["name"]}],
"assigned_networks": self.sriov_nic["assigned_networks"]
})
self.node_nics_put_check_error(
"Node '{0}', bond interface 'ovs-bond0': doesn't have "
"bond_properties.type__".format(self.env.nodes[0]["id"]))
def test_nics_bond_create_failed_without_bond_properties(self):
self.data.append({
"name": 'ovs-bond0',
"type": NETWORK_INTERFACE_TYPES.bond,
"mode": BOND_MODES.balance_slb,
"slaves": [
{"name": self.admin_nic["name"]},
{"name": self.sriov_nic["name"]}],
"assigned_networks": self.sriov_nic["assigned_networks"]
})
self.node_nics_put_check_error(
"Node '{0}', bond interface 'ovs-bond0': doesn't have "
"bond_properties".format(self.env.nodes[0]["id"]))
def test_nics_bond_create_failed_with_unexpected_type__(self):
self.data.append({
"name": 'ovs-bond0',
"type": NETWORK_INTERFACE_TYPES.bond,
"bond_properties": {
"mode": BOND_MODES.balance_slb,
"type__": 'unexpected_type',
},
"slaves": [
{"name": self.admin_nic["name"]},
{"name": self.sriov_nic["name"]}],
"assigned_networks": self.sriov_nic["assigned_networks"]
})
self.node_nics_put_check_error(
"Node '{0}', interface 'ovs-bond0': unknown type__ "
"'unexpected_type'. type__ should be in '{1}'".format(
self.env.nodes[0]["id"], ','.join([k for k in BOND_TYPES])))
def test_each_bond_type_has_allowed_mode(self):
for bond_type in BOND_TYPES:
self.assertIsNotNone(
network.NetAssignmentValidator.get_allowed_modes_for_bond_type(
bond_type)
)
def test_nics_bond_create_failed_with_incorrect_mode_for_type(self):
self.data.append({
"name": 'ovs-bond0',
"type": NETWORK_INTERFACE_TYPES.bond,
"bond_properties": {
"mode": BOND_MODES.balance_rr,
"type__": BOND_TYPES.ovs,
},
"slaves": [
{"name": self.admin_nic["name"]},
{"name": self.sriov_nic["name"]}],
"assigned_networks": self.sriov_nic["assigned_networks"]
})
allowed_modes = (BOND_MODES.active_backup,
BOND_MODES.balance_slb,
BOND_MODES.balance_tcp,
BOND_MODES.lacp_balance_tcp,
)
self.node_nics_put_check_error(
"Node '{0}', bond interface 'ovs-bond0': mode '{1}' is not "
"allowed for type '{2}'. Allowed modes for '{2}' "
"type: '{3}'".format(
self.env.nodes[0]["id"], BOND_MODES.balance_rr, BOND_TYPES.ovs,
allowed_modes))

View File

@ -367,15 +367,37 @@ class NetAssignmentValidator(BasicValidator):
"must have name".format(node['id'], iface['name']),
log_message=True
)
if 'bond_properties' in iface:
for k in iface['bond_properties'].keys():
if k not in consts.BOND_PROPERTIES:
raise errors.InvalidData(
"Node '{0}', interface '{1}': unknown bond "
"property '{2}'".format(
node['id'], iface['name'], k),
log_message=True
)
if 'bond_properties' not in iface:
raise errors.InvalidData(
"Node '{0}', bond interface '{1}': doesn't have "
"bond_properties".format(node['id'], iface['name']),
log_message=True
)
for k in iface['bond_properties']:
if k not in consts.BOND_PROPERTIES:
raise errors.InvalidData(
"Node '{0}', interface '{1}': unknown bond "
"property '{2}'".format(
node['id'], iface['name'], k),
log_message=True
)
if 'type__' not in iface['bond_properties']:
raise errors.InvalidData(
"Node '{0}', bond interface '{1}': doesn't have "
"bond_properties.type__".format(
node['id'], iface['name']),
log_message=True
)
bond_type = iface['bond_properties']['type__']
if bond_type not in consts.BOND_TYPES:
raise errors.InvalidData(
"Node '{0}', interface '{1}': unknown type__ '{2}'. "
"type__ should be in '{3}'".format(
node['id'], iface['name'], bond_type,
','.join(consts.BOND_TYPES)),
log_message=True
)
bond_mode = cls.get_bond_mode(iface)
if not bond_mode:
raise errors.InvalidData(
@ -390,6 +412,17 @@ class NetAssignmentValidator(BasicValidator):
node['id'], iface['name'], bond_mode),
log_message=True
)
allowed_modes = cls.get_allowed_modes_for_bond_type(bond_type)
if bond_mode not in allowed_modes:
raise errors.InvalidData(
"Node '{0}', bond interface '{1}': mode '{2}' "
"is not allowed for type '{3}'. Allowed modes for "
"'{3}' type: '{4}'".format(
node['id'], iface['name'], bond_mode,
bond_type, allowed_modes),
log_message=True
)
if 'assigned_networks' not in iface or \
not isinstance(iface['assigned_networks'], list):
raise errors.InvalidData(
@ -436,6 +469,30 @@ class NetAssignmentValidator(BasicValidator):
bond_mode = iface['bond_properties']['mode']
return bond_mode
@classmethod
def get_allowed_modes_for_bond_type(cls, bond_type):
if (bond_type == consts.BOND_TYPES.ovs or
bond_type == consts.BOND_TYPES.dpdkovs):
allowed_modes = (consts.BOND_MODES.active_backup,
consts.BOND_MODES.balance_slb,
consts.BOND_MODES.balance_tcp,
consts.BOND_MODES.lacp_balance_tcp,
)
elif bond_type == consts.BOND_TYPES.linux:
allowed_modes = (consts.BOND_MODES.active_backup,
consts.BOND_MODES.balance_rr,
consts.BOND_MODES.balance_xor,
consts.BOND_MODES.broadcast,
consts.BOND_MODES.l_802_3ad,
consts.BOND_MODES.balance_tlb,
consts.BOND_MODES.balance_alb,
)
else:
return None
return allowed_modes
@classmethod
def validate_collection_structure_and_data(cls, webdata):
data = cls.validate_json(webdata)

View File

@ -609,13 +609,11 @@ class TestNovaNetworkOrchestratorSerializer61(OrchestratorSerializerTestBase):
)
for node in cluster.nodes:
self.move_network(node.id, 'management', 'eth0', 'eth1')
self.env.make_bond_via_api('lnx_bond',
'',
['eth1', 'eth2'],
node.id,
bond_properties={
'mode': consts.BOND_MODES.balance_rr
})
self.env.make_bond_via_api(
'lnx_bond', '', ['eth1', 'eth2'], node.id,
bond_properties={'mode': consts.BOND_MODES.balance_rr,
'type__': consts.BOND_TYPES.linux}
)
serializer = self.create_serializer(cluster)
facts = serializer.serialize(cluster, cluster.nodes)
for node in facts:
@ -659,13 +657,11 @@ class TestNovaNetworkOrchestratorSerializer61(OrchestratorSerializerTestBase):
for node in cluster.nodes:
self.move_network(node.id, 'management', 'eth0', 'eth1')
self.move_network(node.id, 'fixed', 'eth0', 'eth1')
self.env.make_bond_via_api('lnx_bond',
'',
['eth1', 'eth2'],
node.id,
bond_properties={
'mode': consts.BOND_MODES.balance_rr
})
self.env.make_bond_via_api(
'lnx_bond', '', ['eth1', 'eth2'], node.id,
bond_properties={'mode': consts.BOND_MODES.balance_rr,
'type__': consts.BOND_TYPES.linux}
)
serializer = self.create_serializer(cluster)
facts = serializer.serialize(cluster, cluster.nodes)
for node in facts:
@ -939,16 +935,12 @@ class TestNeutronOrchestratorSerializer61(OrchestratorSerializerTestBase):
nic_count=3)
for node in cluster.nodes:
self.move_network(node.id, 'storage', 'eth0', 'eth1')
self.env.make_bond_via_api('lnx_bond',
'',
['eth1', 'eth2'],
node.id,
bond_properties={
'mode': consts.BOND_MODES.balance_rr
},
interface_properties={
'mtu': 9000
})
self.env.make_bond_via_api(
'lnx_bond', '', ['eth1', 'eth2'], node.id,
bond_properties={'mode': consts.BOND_MODES.balance_rr,
'type__': consts.BOND_TYPES.linux},
interface_properties={'mtu': 9000}
)
serializer = self.create_serializer(cluster)
facts = serializer.serialize(cluster, cluster.nodes)
for node in facts:
@ -2222,13 +2214,16 @@ class TestNeutronOrchestratorSerializerBonds(OrchestratorSerializerTestBase):
}
self.datadiff(msg, expected, compare_sorted=True)
def check_bond_with_mode(self, mode):
def check_bond_with_mode(self, mode, bond_type):
cluster = self.create_env()
for node in cluster.nodes:
self.env.make_bond_via_api('ovsbond0',
mode,
['eth1', 'eth2'],
node.id)
node.id,
bond_properties={
'type__': bond_type}
)
facts = self.serialize(cluster)
for node in facts:
transforms = node['network_scheme']['transformations']
@ -2242,8 +2237,16 @@ class TestNeutronOrchestratorSerializerBonds(OrchestratorSerializerTestBase):
def test_bonds_serialization(self):
self.create_release()
from nailgun.extensions.network_manager.validators.network \
import NetAssignmentValidator
ovs_modes = NetAssignmentValidator.get_allowed_modes_for_bond_type(
consts.BOND_TYPES.ovs)
for mode in consts.BOND_MODES:
self.check_bond_with_mode(mode)
if mode in ovs_modes:
bond_type = consts.BOND_TYPES.ovs
else:
bond_type = consts.BOND_TYPES.linux
self.check_bond_with_mode(mode, bond_type)
class TestCephOsdImageOrchestratorSerialize(OrchestratorSerializerTestBase):

View File

@ -214,7 +214,8 @@ class TestProvisioningSerializer(BaseIntegrationTest):
['eth1', 'eth4'],
node['id'],
bond_properties={
'mode': consts.BOND_MODES.balance_rr
'mode': consts.BOND_MODES.balance_rr,
'type__': consts.BOND_TYPES.linux
})
# check serialized data
serialized_node = ps.serialize(self.cluster_db, [node_db])['nodes'][0]

View File

@ -286,10 +286,10 @@ class TestNetworkVerificationWithBonds(BaseIntegrationTest):
for node in self.env.nodes:
data, admin_nic, other_nic, empty_nic = self.verify_nics(node)
self.env.make_bond_via_api("ovs-bond0",
consts.BOND_MODES.balance_slb,
[other_nic["name"], empty_nic["name"]],
node["id"])
self.env.make_bond_via_api(
"ovs-bond0", consts.BOND_MODES.balance_slb,
[other_nic["name"], empty_nic["name"]], node["id"],
bond_properties={'type__': consts.BOND_TYPES.ovs})
self.verify_bonds(node)
def verify_nics(self, node):

View File

@ -260,7 +260,8 @@ class TestInstallationInfo(BaseTestCase):
self.env.make_bond_via_api(
'bond0', consts.BOND_MODES.active_backup,
['eth1', 'eth2'], node_id=self.env.nodes[0].id)
['eth1', 'eth2'], node_id=self.env.nodes[0].id,
bond_properties={'type__': consts.BOND_TYPES.linux})
nodes_info = info.get_nodes_info(self.env.nodes)
self.assertEquals(len(self.env.nodes), len(nodes_info))
for idx, node in enumerate(self.env.nodes):