Fix bug with changing offloading modes for bonds

* Change offloading_modes field in DB model to mutable
 * Manually mark it as 'changed' after changing modes
 * Add MutableList class (TMP. Till it will be added in sqlalchemy.)

Closes-bug: #1480169
Change-Id: I0f5f3d195540777e449a6bacba67991afcc32f3d
This commit is contained in:
Fedor Zhadaev 2015-07-31 18:21:31 +03:00
parent e390cf8701
commit 62a1a7e5ec
4 changed files with 103 additions and 1 deletions

View File

@ -0,0 +1,54 @@
# -*- coding: utf-8 -*-
# Copyright 2015 Mirantis, Inc.
#
# 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.
from sqlalchemy.ext.mutable import Mutable
class MutableList(Mutable, list):
# TODO(fzhadaev): delete this class after it will be
# implemented in sqlalchemy lib.
# https://bitbucket.org/zzzeek/sqlalchemy/issues/3297
@classmethod
def coerce(cls, key, value):
"""Convert plain lists to MutableList."""
if not isinstance(value, MutableList):
if isinstance(value, list):
return MutableList(value)
# this call will raise ValueError
return Mutable.coerce(key, value)
else:
return value
def __setitem__(self, key, value):
"""Detect list set events and emit change events."""
list.__setitem__(self, key, value)
self.changed()
def __delitem__(self, key):
"""Detect list del events and emit change events."""
list.__delitem__(self, key)
self.changed()
def __getstate__(self):
return list(self)
def __setstate__(self, state):
self[:] = state

View File

@ -33,6 +33,7 @@ from nailgun import consts
from nailgun.db.sqlalchemy.models.base import Base
from nailgun.db.sqlalchemy.models.fields import JSON
from nailgun.db.sqlalchemy.models.fields import LowercaseString
from nailgun.db.sqlalchemy.models.mutable import MutableList
from nailgun.db.sqlalchemy.models.network import NetworkBondAssignment
from nailgun.db.sqlalchemy.models.network import NetworkNICAssignment
from nailgun.extensions.volume_manager.manager import VolumeManager
@ -266,7 +267,8 @@ class NodeNICInterface(Base):
bus_info = Column(Text)
pxe = Column(Boolean, default=False, nullable=False)
offloading_modes = Column(JSON, default=[], nullable=False,
offloading_modes = Column(MutableList.as_mutable(JSON),
default=[], nullable=False,
server_default='[]')
@property
@ -377,6 +379,7 @@ class NodeBondInterface(Base):
NodeNICInterface.offloading_modes_as_flat_dict(new_modes)
for interface in self.slaves:
self._update_modes(interface.offloading_modes, new_modes_dict)
interface.offloading_modes.changed()
def _update_modes(self, modes, update_dict):
for mode in modes:

View File

@ -782,6 +782,9 @@ class NetworkManager(object):
node_id=node_db.id
).first()
)
bond_db.offloading_modes = bond.get('offloading_modes', {})
db().commit()
return node_db.id

View File

@ -613,3 +613,45 @@ class TestNodeNICsBonding(BaseIntegrationTest):
"and doesn't contain node's pxe interface 'eth0'".format(
self.env.nodes[0]["id"])
)
def test_nics_bond_change_offloading_modes(self):
self.get_node_nics_info()
self.nics_bond_create(self.put_single)
resp = self.app.get(
reverse("NodeNICsHandler",
kwargs={"node_id": self.env.nodes[0]["id"]}),
headers=self.default_headers)
self.assertEqual(200, resp.status_code)
body = resp.json_body
bonds = filter(
lambda iface: iface["type"] == NETWORK_INTERFACE_TYPES.bond,
body)
self.assertEqual(1, len(bonds))
bond_offloading_modes = bonds[0]['offloading_modes']
self.assertEqual(len(bond_offloading_modes), 1)
slaves = bonds[0]['slaves']
self.assertEqual(2, len(slaves))
self.assertIsNone(bond_offloading_modes[0]['state'])
bond_offloading_modes[0]['state'] = True
self.assertTrue(bond_offloading_modes[0]['state'])
resp = self.env.node_nics_put(
self.env.nodes[0]["id"],
body)
body = resp.json_body
bonds = filter(
lambda iface: iface["type"] == NETWORK_INTERFACE_TYPES.bond,
body)
self.assertEqual(1, len(bonds))
bond_offloading_modes = bonds[0]['offloading_modes']
self.assertEqual(len(bond_offloading_modes), 1)
slaves = bonds[0]['slaves']
self.assertEqual(2, len(slaves))
self.assertTrue(bond_offloading_modes[0]['state'])