Stick 'pxe' role to physical interface

* add 'pxe' property to the nic db model
* collect 'pxe' property during the
  bootstrap stage
* forbid to assign admin net to non pxe interfaces
* allow to assign admin net only to bond interface
  what containing pxe interface

Change-Id: I70dcaed66607728b76ae3d93c59048c310ddb22c
Implements: blueprint admin-network-on-bond
This commit is contained in:
Valyavskiy Viacheslav 2015-07-01 16:23:27 +03:00
parent 3b96ea59de
commit 4bf1095593
19 changed files with 369 additions and 141 deletions

View File

@ -206,6 +206,7 @@ class NodeAgent
:memory => (_dmi_memory or _ohai_memory),
}
admin_mac = _master_ip_and_mac[:mac] rescue nil
begin
(@os[:network][:interfaces] or {} rescue {}).each do |int, intinfo|
# Send info about physical interfaces only
@ -220,6 +221,7 @@ class NodeAgent
(intinfo[:addresses] or {} rescue {}).each do |addr, addrinfo|
if (addrinfo[:family] rescue nil) =~ /lladdr/
int_meta[:mac] = addr
int_meta[:pxe] = admin_mac == int_meta[:mac]
begin
int_info = Rethtool::InterfaceSettings.new(int)
int_meta[:driver] = int_info.driver

View File

@ -68,6 +68,7 @@ single_schema = {
}
},
"pxe": {"type": "boolean"}
}
}
},

View File

@ -22,6 +22,7 @@ from nailgun.db import db
from nailgun.db.sqlalchemy.models import Cluster
from nailgun.db.sqlalchemy.models import Node
from nailgun.errors import errors
import six
class NetworkConfigurationValidator(BasicValidator):
@ -274,22 +275,43 @@ class NetAssignmentValidator(BasicValidator):
network_group_ids = net_manager.get_node_networkgroups_ids(db_node)
bonded_eth_ids = set()
pxe_iface_name = net_manager._get_pxe_iface_name(db_node)
if not pxe_iface_name:
raise errors.InvalidData(
"Node '{0}': Interfaces configuration can't be changed if"
"there is no pxe interface in DB".format(node['id']),
log_message=True
)
for iface in interfaces:
iface_nets = [n.get('name')
for n in iface.get('assigned_networks')]
if iface['type'] == consts.NETWORK_INTERFACE_TYPES.ether:
db_iface = filter(
db_iface = next(six.moves.filter(
lambda i: i.id == iface['id'],
db_interfaces
)
), None)
if not db_iface:
raise errors.InvalidData(
"Node '{0}': there is no interface with ID '{1}'"
" in DB".format(node['id'], iface['id']),
log_message=True
)
if not db_iface.pxe:
if consts.NETWORKS.fuelweb_admin in iface_nets:
raise errors.InvalidData(
"Node '{0}': admin network can not be assigned to"
" non-pxe interface {1}".format(node['id'],
iface['name']),
log_message=True
)
elif iface['type'] == consts.NETWORK_INTERFACE_TYPES.bond:
pxe_iface_present = False
for slave in iface['slaves']:
iface_id = [i.id for i in db_interfaces
if i.name == slave['name']]
if slave["name"] == pxe_iface_name:
pxe_iface_present = True
if iface_id:
if iface_id[0] in bonded_eth_ids:
raise errors.InvalidData(
@ -307,7 +329,6 @@ class NetAssignmentValidator(BasicValidator):
log_message=True
)
iface_nets = [n['name'] for n in iface['assigned_networks']]
if consts.NETWORKS.fuelweb_admin in iface_nets:
prohibited_modes = net_manager.\
get_prohibited_admin_bond_modes()
@ -319,6 +340,14 @@ class NetAssignmentValidator(BasicValidator):
node['id'], iface['name'], bond_mode),
log_message=True
)
if not pxe_iface_present:
raise errors.InvalidData(
"Node '{0}': interface '{1}' belongs to "
"admin network and doesn't contain node's pxe "
"interface '{2}'".format(
node['id'], iface['name'], pxe_iface_name),
log_message=True
)
for net in iface['assigned_networks']:
if net['id'] not in network_group_ids:

View File

@ -85,9 +85,11 @@ def upgrade():
extend_releases_model_upgrade()
upgrade_task_names()
vms_conf_upgrade()
extend_nic_model_upgrade()
def downgrade():
extend_nic_model_downgrade()
extend_releases_model_downgrade()
migrate_volumes_into_extension_downgrade()
node_roles_as_plugin_downgrade()
@ -433,3 +435,29 @@ def node_roles_as_plugin_downgrade():
def extend_releases_model_downgrade():
op.drop_column('releases', 'network_roles_metadata')
def extend_nic_model_upgrade():
connection = op.get_bind()
op.add_column(
'node_nic_interfaces',
sa.Column('pxe',
sa.Boolean,
nullable=False,
server_default='false'))
select_query = sa.sql.text(
"SELECT ni.id from node_nic_interfaces ni "
"join net_nic_assignments na on ni.id=na.interface_id "
"join network_groups ng on ng.id=na.network_id "
"WHERE ng.name = 'fuelweb_admin'")
update_query = sa.sql.text(
"UPDATE node_nic_interfaces SET pxe = true "
"WHERE id = :id")
# change 'pxe' property to 'true' value for admin ifaces
for iface_id in connection.execute(select_query):
connection.execute(update_query, id=iface_id[0])
def extend_nic_model_downgrade():
op.drop_column('node_nic_interfaces', 'pxe')

View File

@ -247,6 +247,7 @@ class NodeNICInterface(Base):
parent_id = Column(Integer, ForeignKey('node_bond_interfaces.id'))
driver = Column(Text)
bus_info = Column(Text)
pxe = Column(Boolean, default=False, nullable=False)
offloading_modes = Column(JSON, default=[], nullable=False,
server_default='[]')

View File

@ -148,7 +148,8 @@
"state": null,
"sub": []
}
]
],
"pxe": false
},
{
"mac": "00:25:90:6a:b1:11",
@ -185,7 +186,8 @@
"state": null,
"sub": []
}
]
],
"pxe": true
}
],
"disks": [
@ -398,7 +400,8 @@
"state": null,
"sub": []
}
]
],
"pxe": true
},
{
"ip": "192.168.70.234",
@ -435,7 +438,8 @@
"state": true,
"sub": []
}
]
],
"pxe": false
},
{
"mac": "54:78:ea:05:17:ba",
@ -471,7 +475,8 @@
"state": true,
"sub": []
}
]
],
"pxe": false
}
],
"disks": [
@ -588,7 +593,8 @@
"driver": "igb",
"bus_info": "0000:06:00.0",
"max_speed": 1000,
"current_speed": 1000
"current_speed": 1000,
"pxe": false
},
{
"name": "eth2",
@ -598,7 +604,8 @@
"driver": "igb",
"bus_info": "0000:07:00.0",
"max_speed": 1000,
"current_speed": 1000
"current_speed": 1000,
"pxe": false
},
{
"name": "eth3",
@ -608,7 +615,8 @@
"driver": "eth_ipoib",
"bus_info": "0000:08:00.0",
"max_speed": 56000,
"current_speed": 56000
"current_speed": 56000,
"pxe": false
},
{
"ip": "10.20.0.5",
@ -617,7 +625,8 @@
"name": "eth0",
"current_speed": null,
"driver": "igb",
"bus_info": "0000:09:00.0"
"bus_info": "0000:09:00.0",
"pxe": true
}
],
"disks": [
@ -734,7 +743,8 @@
"name": "eth1",
"current_speed": null,
"driver": "mlx4_en",
"bus_info": "0000:10:00.0"
"bus_info": "0000:10:00.0",
"pxe": false
},
{
"name": "eth0",
@ -744,7 +754,8 @@
"bus_info": "0000:11:00.0",
"mac": "00:25:90:67:9d:24",
"max_speed": 1000,
"current_speed": 1000
"current_speed": 1000,
"pxe": true
}
],
"disks": [
@ -863,7 +874,8 @@
"current_speed": null,
"ip": "10.20.0.7",
"driver": "igb",
"bus_info": "0000:12:00.0"
"bus_info": "0000:12:00.0",
"pxe": true
},
{
"name": "eth0",
@ -872,7 +884,8 @@
"driver": "igb",
"bus_info": "0000:13:00.0",
"max_speed": 1000,
"current_speed": 1000
"current_speed": 1000,
"pxe": false
}
],
"disks": [
@ -966,7 +979,8 @@
"driver": "e1000",
"bus_info": "0000:14:00.0",
"max_speed": 100,
"current_speed": 100
"current_speed": 100,
"pxe": true
},
{
"name": "eth1",
@ -974,7 +988,8 @@
"max_speed": 1000,
"current_speed": 100,
"driver": "e1000",
"bus_info": "0000:15:00.0"
"bus_info": "0000:15:00.0",
"pxe": false
},
{
"name": "eth2",
@ -982,7 +997,8 @@
"max_speed": 100,
"current_speed": null,
"driver": "e1000",
"bus_info": "0000:16:00.0"
"bus_info": "0000:16:00.0",
"pxe": false
},
{
"name": "eth3",
@ -990,7 +1006,8 @@
"max_speed": 100,
"current_speed": null,
"driver": "e1000",
"bus_info": "0000:17:00.0"
"bus_info": "0000:17:00.0",
"pxe": false
}
],
"disks": [
@ -1057,7 +1074,8 @@
"max_speed": 100,
"current_speed": 100,
"driver": "igb",
"bus_info": "0000:18:00.0"
"bus_info": "0000:18:00.0",
"pxe": true
},
{
"name": "eth1",
@ -1065,7 +1083,8 @@
"max_speed": 1000,
"current_speed": 1000,
"driver": "igb",
"bus_info": "0000:19:00.0"
"bus_info": "0000:19:00.0",
"pxe": false
},
{
"name": "eth2",
@ -1073,7 +1092,8 @@
"max_speed": 100,
"current_speed": null,
"driver": "igb",
"bus_info": "0000:20:00.0"
"bus_info": "0000:20:00.0",
"pxe": false
},
{
"name": "eth3",
@ -1081,7 +1101,8 @@
"max_speed": 1000,
"current_speed": 100,
"driver": "igb",
"bus_info": "0000:21:00.0"
"bus_info": "0000:21:00.0",
"pxe": false
},
{
"name": "eth4",
@ -1089,7 +1110,8 @@
"max_speed": 56000,
"current_speed": 56000,
"driver": "mlx4_en",
"bus_info": "0000:22:00.0"
"bus_info": "0000:22:00.0",
"pxe": false
},
{
"name": "eth5",
@ -1097,7 +1119,8 @@
"max_speed": 100,
"current_speed": 100,
"driver": "igb",
"bus_info": "0000:23:00.0"
"bus_info": "0000:23:00.0",
"pxe": false
}
],
"disks": [
@ -1254,7 +1277,8 @@
"max_speed": 1000,
"current_speed": 1000,
"driver": "igb",
"bus_info": "0000:24:00.0"
"bus_info": "0000:24:00.0",
"pxe": false
},
{
"ip": "10.20.0.7",
@ -1263,7 +1287,8 @@
"name": "p2p2",
"current_speed": null,
"driver": "igb",
"bus_info": "0000:25:00.0"
"bus_info": "0000:25:00.0",
"pxe": true
}
],
"disks": [

View File

@ -400,6 +400,37 @@ class NetworkManager(object):
return ips.all()
@classmethod
def _get_pxe_iface_name(cls, node):
"""Returns appropriate pxe iface's name
In case when node has network scheme configured
we can not rely on its pxe interface calculation
algorithm anymore, because admin ip is moving to
bridge and 'pxe' property will have 'False' value
for all interfaces. In this case we should rely on
db where actual pxe interface was saved during the
bootstrap stage.
In case when node for some reason has no pxe interface
in db we should get pxe interface using appropriate
function `get_admin_physical_iface`.
"""
db_interfaces = node.nic_interfaces
pxe = next((
i for i in node.meta['interfaces'] if i.get('pxe') or
i.get('mac') == node.mac),
None)
if pxe:
return pxe.get('name')
pxe_db = next((i for i in db_interfaces if i.pxe), None)
if pxe_db:
return pxe_db.name
if db_interfaces:
return objects.Node.get_admin_physical_iface(node).name
logger.warning(u'Cannot find pxe interface for node "%s"',
node.full_name)
return None
@classmethod
def clear_assigned_ips(cls, node):
db().query(IPAddr).filter_by(node=node.id).delete()
@ -694,8 +725,11 @@ class NetworkManager(object):
except errors.InvalidInterfacesInfo as e:
logger.debug("Cannot update interfaces: %s", e.message)
return
pxe_iface_name = cls._get_pxe_iface_name(node)
for interface in node.meta["interfaces"]:
# set 'pxe' property for appropriate iface
if interface['name'] == pxe_iface_name:
interface['pxe'] = True
# try to get interface by mac address
interface_db = next((
n for n in node.nic_interfaces
@ -794,6 +828,7 @@ class NetworkManager(object):
interface.state = interface_attrs.get('state')
interface.driver = interface_attrs.get('driver')
interface.bus_info = interface_attrs.get('bus_info')
interface.pxe = interface_attrs.get('pxe', False)
if interface_attrs.get('interface_properties'):
interface.interface_properties = \
interface_attrs['interface_properties']

View File

@ -63,7 +63,8 @@ class NodeInterfacesSerializer(BasicSerializer):
'assigned_networks',
'driver',
'bus_info',
'offloading_modes'
'offloading_modes',
'pxe'
)
bond_fields = (
'mac',

View File

@ -334,9 +334,10 @@ class EnvironmentManager(object):
if_list = [
{
"name": "eth{0}".format(i),
"mac": self.generate_random_mac()
"mac": self.generate_random_mac(),
}
for i in range(if_count)]
if_list[0]['pxe'] = True
self.set_interfaces_in_meta(meta, if_list)
nodes.append(self.create_node(meta=meta, **kwargs))
return nodes

View File

@ -463,7 +463,8 @@ class TestNodeNICAdminAssigning(BaseIntegrationTest):
self.env.generate_random_mac())
meta = self.env.default_metadata()
meta['interfaces'] = [{'name': 'eth0', 'mac': mac1},
{'name': 'eth1', 'mac': mac2, 'ip': admin_ip}]
{'name': 'eth1', 'mac': mac2, 'ip': admin_ip,
'pxe': True}]
self.env.create_node(api=True, meta=meta, mac=mac1,
cluster_id=cluster['id'])
node_db = self.env.nodes[0]
@ -517,7 +518,7 @@ class TestNodePublicNetworkToNICAssignment(BaseIntegrationTest):
{'name': 'eth3', 'mac': self.env.generate_random_mac()},
{'name': 'eth2', 'mac': self.env.generate_random_mac()},
{'name': 'eth0', 'mac': self.env.generate_random_mac(),
'ip': admin_ip},
'ip': admin_ip, 'pxe': True},
{'name': 'eth1', 'mac': self.env.generate_random_mac()}
]
node = self.env.create_node(api=True, meta=meta,
@ -556,13 +557,19 @@ class TestNodeNICsHandlersValidation(BaseIntegrationTest):
def setUp(self):
super(TestNodeNICsHandlersValidation, self).setUp()
meta = self.env.default_metadata()
meta["interfaces"] = [
{'name': 'eth0', 'mac': self.env.generate_random_mac(),
'pxe': True},
{'name': 'eth1', 'mac': self.env.generate_random_mac()},
]
self.env.create(
cluster_kwargs={
"net_provider": "neutron",
"net_segment_type": "gre"
},
nodes_kwargs=[
{"api": True, "pending_addition": True}
{"api": True, "pending_addition": True, 'meta': meta}
]
)
resp = self.app.get(
@ -625,3 +632,12 @@ class TestNodeNICsHandlersValidation(BaseIntegrationTest):
"Node '{0}': there is no interface with ID '1234567'"
" in DB".format(self.env.nodes[0]["id"])
)
def test_nic_assignment_failed_assign_admin_net_to_non_pxe_iface(self):
admin_net = self.nics_w_nets[0]["assigned_networks"][0]
del self.nics_w_nets[0]["assigned_networks"][0]
self.nics_w_nets[1]["assigned_networks"].append(admin_net)
self.node_nics_put_check_error(
"Node '{0}': admin network can not be assigned to non-pxe"
" interface eth1".format(self.env.nodes[0]["id"])
)

View File

@ -31,7 +31,7 @@ class TestNodeCollectionNICsHandler(BaseIntegrationTest):
mac = self.env.generate_random_mac()
meta = {}
self.env.set_interfaces_in_meta(meta, [
{'name': 'eth0', 'mac': mac},
{'name': 'eth0', 'mac': mac, 'pxe': True},
{'name': 'eth1', 'mac': self.env.generate_random_mac()}])
node = self.env.create_node(api=True, meta=meta, mac=mac,
cluster_id=cluster['id'])
@ -63,10 +63,12 @@ class TestNodeCollectionNICsHandler(BaseIntegrationTest):
# Creating cluster with node
self.env.create_cluster()
cluster = self.env.clusters[0]
self.env.create_node(
self.env.create_nodes_w_interfaces_count(
roles=['controller'],
pending_addition=True,
cluster_id=cluster.id
cluster_id=cluster.id,
nodes_count=1,
if_count=4
)
# Deploying cluster
deployment_task = self.env.launch_deployment()
@ -108,8 +110,12 @@ class TestNodeCollectionNICsHandler(BaseIntegrationTest):
consts.NODE_STATUSES.deploying: True,
consts.NODE_STATUSES.ready: True,
consts.NODE_STATUSES.removing: True}
meta = self.env.default_metadata()
meta['interfaces'] = [{'name': 'eth0', 'pxe': True},
{'name': 'eth1'}]
self.env.create_node(
roles=['controller'],
meta=meta
)
node = self.env.nodes[0]
for status, lock in six.iteritems(lock_vs_status):

View File

@ -182,14 +182,16 @@ class TestHandlers(BaseIntegrationTest):
'name': 'eth0',
'mac': mac_eth0,
'current_speed': 1,
'state': 'up'
'state': 'up',
'pxe': True
}
eth1 = {
'name': 'eth1',
'mac': mac_eth1,
'current_speed': 1,
'state': 'up'
'state': 'up',
'pxe': False
}
# prepare metadata with our interfaces
@ -412,7 +414,7 @@ class TestHandlers(BaseIntegrationTest):
meta = self.env.default_metadata()
self.env.set_interfaces_in_meta(meta, [
{'name': 'eth0', 'mac': '00:00:00:00:00:00', 'current_speed': 1,
'state': 'up'}])
'state': 'up', 'pxe': True}])
self.env.create_node(api=True, meta=meta)
new_meta = deepcopy(meta)
node = self.env.nodes[0]
@ -446,7 +448,7 @@ class TestHandlers(BaseIntegrationTest):
meta = self.env.default_metadata()
self.env.set_interfaces_in_meta(meta, [
{'name': 'eth0', 'mac': '00:00:00:00:00:00', 'current_speed': 1,
'state': 'up'}])
'pxe': True, 'state': 'up'}])
node = self.env.create_node(api=True, meta=meta)
node_data = {'mac': node['mac'], 'meta': meta}
# check default interface_properties values
@ -487,7 +489,7 @@ class TestHandlers(BaseIntegrationTest):
meta = self.env.default_metadata()
self.env.set_interfaces_in_meta(meta, [
{'name': 'eth0', 'mac': '00:00:00:00:00:00', 'current_speed': 1,
'state': 'up'}])
'pxe': True, 'state': 'up'}])
node = self.env.create_node(api=True, meta=meta)
meta['interfaces'].append({
@ -622,7 +624,8 @@ class TestHandlers(BaseIntegrationTest):
meta = self.env.default_metadata()
meta["interfaces"] = [
{'name': 'eth0', 'mac': self.env.generate_random_mac()},
{'name': 'eth0', 'mac': self.env.generate_random_mac(),
'pxe': True},
{'name': 'eth1', 'mac': self.env.generate_random_mac()},
{'name': 'eth2', 'mac': self.env.generate_random_mac()},
{'name': 'eth3', 'mac': self.env.generate_random_mac()},

View File

@ -33,6 +33,7 @@ class TestNodeNICsBonding(BaseIntegrationTest):
self.env.set_interfaces_in_meta(meta, [
{"name": "eth0",
"mac": "00:00:00:00:00:66",
"pxe": True,
"offloading_modes": [
{
"name": "mode_1",
@ -80,6 +81,7 @@ class TestNodeNICsBonding(BaseIntegrationTest):
"sub": []
}
]}])
self.env.create(
cluster_kwargs={
"net_provider": "neutron",
@ -588,3 +590,26 @@ class TestNodeNICsBonding(BaseIntegrationTest):
resp = self.put_single()
self.assertEqual(resp.status_code, 200)
def test_nics_bond_create_failed_admin_net_w_o_pxe_iface(self):
mode = BOND_MODES.balance_slb
bond_nets = [self.admin_nic["assigned_networks"][0]] + \
self.other_nic["assigned_networks"]
del self.admin_nic["assigned_networks"][0]
self.data.append({
"name": 'ovs-bond0',
"type": NETWORK_INTERFACE_TYPES.bond,
"mode": mode,
"slaves": [
{"name": self.empty_nic["name"]},
{"name": self.other_nic["name"]}],
"assigned_networks": bond_nets
})
self.other_nic["assigned_networks"] = []
self.node_nics_put_check_error(
"Node '{0}': interface 'ovs-bond0' belongs to admin network "
"and doesn't contain node's pxe interface 'eth0'".format(
self.env.nodes[0]["id"])
)

View File

@ -158,7 +158,7 @@ class TestProvisioningSerializer(BaseIntegrationTest):
admin_mac = self.env.generate_random_mac()
meta = {
'interfaces': [
{'name': 'eth1', 'mac': self.env.generate_random_mac()},
{'name': 'eth1', 'mac': admin_mac, 'pxe': True},
{'name': 'eth2', 'mac': self.env.generate_random_mac()},
{'name': 'eth3', 'mac': self.env.generate_random_mac()},
{'name': 'eth4', 'mac': self.env.generate_random_mac()}

View File

@ -22,12 +22,16 @@ class TestPutSameJson(base.BaseIntegrationTest):
def setUp(self):
super(TestPutSameJson, self).setUp()
meta = self.env.default_metadata()
meta["interfaces"] = [
{'name': 'eth0', 'pxe': True},
{'name': 'eth1'}, {'name': 'eth2'}
]
self.cluster = self.env.create(
cluster_kwargs={'api': True},
nodes_kwargs=[
{'api': True},
{'api': True, 'pending_addition': True},
{'api': True, 'meta': meta},
{'api': True, 'pending_addition': True, 'meta': meta},
]
)
self.cluster = self.env.clusters[0]

View File

@ -306,12 +306,14 @@ class TestNetworkVerificationWithBonds(BaseIntegrationTest):
meta1 = self.env.default_metadata()
meta2 = self.env.default_metadata()
self.env.set_interfaces_in_meta(meta1, [
{"name": "eth0", "mac": "00:00:00:00:00:66"},
{"name": "eth0", "mac": "00:00:00:00:00:66",
"pxe": True},
{"name": "eth1", "mac": "00:00:00:00:00:77"},
{"name": "eth2", "mac": "00:00:00:00:00:88"}]
)
self.env.set_interfaces_in_meta(meta2, [
{"name": "eth0", "mac": "00:00:00:00:11:66", "current_speed": 100},
{"name": "eth0", "mac": "00:00:00:00:11:66", "current_speed": 100,
"pxe": True},
{"name": "eth1", "mac": "00:00:00:00:22:77", "current_speed": 100},
{"name": "eth2", "mac": "00:00:00:00:33:88", "current_speed": 100}]
)

View File

@ -204,24 +204,20 @@ class TestInstallationInfo(BaseTestCase):
def test_nodes_info(self):
info = InstallationInfo()
self.env.create(
cluster = self.env.create(
release_kwargs={
'operating_system': consts.RELEASE_OS.centos
},
nodes_kwargs=[
{'status': consts.NODE_STATUSES.discover,
'roles': ['controller', 'compute'],
'meta': {}},
{'roles': [],
'pending_roles': ['compute'],
'meta': {'cpu': {},
'interfaces': [{'mac': 'x', 'name': 'eth0'}],
'disks': [{'name': 'a', 'disk': 'a'}]}}
]
)
})
self.env.create_nodes_w_interfaces_count(
nodes_count=2,
if_count=4,
roles=['controller', 'compute'],
pending_addition=True,
cluster_id=cluster['id'])
self.env.make_bond_via_api(
'bond0', consts.BOND_MODES.active_backup,
['eth0', 'eth1'], node_id=self.env.nodes[0].id)
['eth1', 'eth2'], node_id=self.env.nodes[0].id)
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):

View File

@ -193,6 +193,55 @@ def prepare():
{'role': mongoroleid, 'node': nodeid_c, 'primary': False},
])
db.execute(
meta.tables['node_nic_interfaces'].insert(),
[
{
'id': 1,
'node_id': nodeid_a,
'name': 'test_interface',
'mac': '00:00:00:00:00:01',
'max_speed': 200,
'current_speed': 100,
'ip_addr': '10.20.0.2',
'netmask': '255.255.255.0',
'state': 'test_state',
'interface_properties': jsonutils.dumps(
{'test_property': 'test_value'}),
'driver': 'test_driver',
'bus_info': 'some_test_info'
},
{
'id': 2,
'node_id': nodeid_a,
'name': 'test_interface_2',
'mac': '00:00:00:00:00:02',
'max_speed': 200,
'current_speed': 100,
'ip_addr': '10.30.0.2',
'netmask': '255.255.255.0',
'state': 'test_state',
'interface_properties': jsonutils.dumps(
{'test_property': 'test_value'}),
'driver': 'test_driver',
'bus_info': 'some_test_info'
},
{
'id': 3,
'node_id': nodeid_a,
'name': 'test_interface_3',
'mac': '00:00:00:00:00:03',
'max_speed': 200,
'current_speed': 100,
'ip_addr': '10.30.0.2',
'netmask': '255.255.255.0',
'state': 'test_state',
'interface_properties': jsonutils.dumps(
{'test_property': 'test_value'}),
'driver': 'test_driver',
'bus_info': 'some_test_info'
}])
db.execute(
meta.tables['node_bond_interfaces'].insert(),
[{
@ -204,22 +253,42 @@ def prepare():
}])
db.execute(
meta.tables['node_nic_interfaces'].insert(),
[{
'node_id': nodeid_a,
'name': 'test_interface',
'mac': '00:00:00:00:00:01',
'max_speed': 200,
'current_speed': 100,
'ip_addr': '10.20.0.2',
'netmask': '255.255.255.0',
'state': 'test_state',
'interface_properties': jsonutils.dumps(
{'test_property': 'test_value'}),
'parent_id': 1,
'driver': 'test_driver',
'bus_info': 'some_test_info'
}])
meta.tables['network_groups'].insert(),
[
{
'id': 1,
'name': 'fuelweb_admin',
'vlan_start': None,
'cidr': '10.20.0.0/24',
'gateway': '10.20.0.200',
},
{
'id': 2,
'name': 'public',
'vlan_start': None,
'cidr': '10.30.0.0/24',
'gateway': '10.30.0.200'
}
]
)
db.execute(
meta.tables['net_nic_assignments'].insert(),
[
{
'network_id': 1,
'interface_id': 1
},
{
'network_id': 2,
'interface_id': 2
},
{
'network_id': 2,
'interface_id': 3
}
]
)
db.commit()
@ -328,68 +397,20 @@ class TestPublicIpRequired(base.BaseAlembicMigrationTest):
class TestInterfacesOffloadingModesMigration(base.BaseAlembicMigrationTest):
def test_old_fields_exists(self):
# check node_nic_interfaces fields
nic_table = self.meta.tables['node_nic_interfaces']
result = db.execute(
sa.select([self.meta.tables['node_nic_interfaces'].c.node_id]))
self.assertEqual(
result.fetchone()[0], 1)
result = db.execute(
sa.select([self.meta.tables['node_nic_interfaces'].c.name]))
self.assertEqual(
result.fetchone()[0], 'test_interface')
result = db.execute(
sa.select([self.meta.tables['node_nic_interfaces'].c.mac]))
self.assertEqual(
result.fetchone()[0], '00:00:00:00:00:01')
result = db.execute(
sa.select([self.meta.tables['node_nic_interfaces'].c.max_speed]))
self.assertEqual(
result.fetchone()[0], 200)
result = db.execute(
sa.select(
[self.meta.tables['node_nic_interfaces'].c.current_speed]))
self.assertEqual(
result.fetchone()[0], 100)
result = db.execute(
sa.select([self.meta.tables['node_nic_interfaces'].c.ip_addr]))
self.assertEqual(
result.fetchone()[0], '10.20.0.2')
result = db.execute(
sa.select([self.meta.tables['node_nic_interfaces'].c.netmask]))
self.assertEqual(
result.fetchone()[0], '255.255.255.0')
result = db.execute(
sa.select([self.meta.tables['node_nic_interfaces'].c.state]))
self.assertEqual(
result.fetchone()[0], 'test_state')
result = db.execute(
sa.select([self.meta.tables['node_nic_interfaces']
.c.interface_properties]))
self.assertEqual(
jsonutils.loads(result.fetchone()[0]),
{'test_property': 'test_value'})
result = db.execute(
sa.select([self.meta.tables['node_nic_interfaces'].c.parent_id]))
self.assertEqual(
result.fetchone()[0], 1)
result = db.execute(
sa.select([self.meta.tables['node_nic_interfaces'].c.driver]))
self.assertEqual(
result.fetchone()[0], 'test_driver')
result = db.execute(
sa.select([self.meta.tables['node_nic_interfaces'].c.bus_info]))
self.assertEqual(
result.fetchone()[0], 'some_test_info')
sa.select([nic_table.c.node_id, nic_table.c.name, nic_table.c.mac,
nic_table.c.max_speed, nic_table.c.current_speed,
nic_table.c.ip_addr, nic_table.c.netmask,
nic_table.c.state, nic_table.c.interface_properties,
nic_table.c.driver, nic_table.c.bus_info]).
where(nic_table.c.id == 1))
res = result.fetchone()
check_res = [1, u'test_interface', u'00:00:00:00:00:01', 200, 100,
u'10.20.0.2', u'255.255.255.0', u'test_state',
u'{"test_property": "test_value"}',
u'test_driver', u'some_test_info']
self.assertListEqual(list(res), check_res)
def test_new_fields_exists_and_empty(self):
# check node_nic_interfaces fields
@ -406,6 +427,37 @@ class TestInterfacesOffloadingModesMigration(base.BaseAlembicMigrationTest):
jsonutils.loads(result.fetchone()[0]), [])
class TestInterfacesPxePropertyMigration(base.BaseAlembicMigrationTest):
def test_old_fields_exists(self):
# check node_nic_interfaces fields
ng_table = self.meta.tables['network_groups']
result = db.execute(
sa.select([ng_table.c.name, ng_table.c.vlan_start,
ng_table.c.cidr, ng_table.c.gateway]).
where(ng_table.c.id == 1))
res = result.fetchone()
check_res = [u'fuelweb_admin', None, u'10.20.0.0/24', u'10.20.0.200']
self.assertListEqual(list(res), check_res)
result = db.execute(
sa.select([self.meta.tables['net_nic_assignments'].c.network_id]))
self.assertEqual(
result.fetchone()[0], 1)
def test_new_field_exists_and_filled(self):
nic_table = self.meta.tables['node_nic_interfaces']
result = db.execute(
sa.select([nic_table.c.pxe]).where(nic_table.c.id == 1))
# check 'pxe' property is true for admin interfaces
self.assertTrue(result.fetchone()[0])
result = db.execute(
sa.select([nic_table.c.pxe]).where(nic_table.c.id != 1))
# and 'false' for any others
for res in result.fetchall():
self.assertFalse(res[0])
class TestMigrateVolumesIntoExtension(base.BaseAlembicMigrationTest):
def test_data_are_moved_into_buffer_table(self):

View File

@ -175,7 +175,8 @@ casper.createNode = function(options) {
"mac": "C8:0A:A9:A6:FF:28",
"name": "eth1",
"max_speed": 1000,
"current_speed": 1000
"current_speed": 1000,
"pxe": true
},
{
"mac": "D4:56:C3:88:99:DF",