[ovn]support read chassis update time from nb_cfg_timestamp

nb_cfg_timestamp: The timestamp when ovn-controller finishes
processing the change corresponding to nb_cfg[1]. it can better
reflect the status of chassis.

This patch updated some unit tests. ensure mock 'time.time' is
stopped after test. if not stop, may affect "timeutils.utcnow_ts"
to obtain the real time, cause test case
'test_agent_with_nb_cfg_timestamp_not_timeout' failure.

Partial-bug: #1938478
[1] https://www.ovn.org/support/dist-docs/ovn-sb.5.html

Conflicts:
  neutron/plugins/ml2/drivers/ovn/agent/neutron_agent.py
  neutron/tests/unit/plugins/ml2/drivers/ovn/mech_driver/test_mech_driver.py
  neutron/tests/unit/agent/l2/extensions/dhcp/test_ipv6.py

Change-Id: Ia74a9404411862dc88b48c4a198d5c53f5f52704
(cherry picked from commit 9e263dcf00)
(cherry picked from commit cfc0678caf)
(cherry picked from commit 538712635c)
This commit is contained in:
zhouhenglc 2021-07-29 15:49:39 +08:00 committed by Rodolfo Alonso Hernandez
parent ef4c9db5a6
commit d34afc5c13
4 changed files with 71 additions and 6 deletions

View File

@ -14,6 +14,7 @@
import abc
import copy
import datetime
from oslo_config import cfg
from oslo_utils import timeutils
@ -44,7 +45,21 @@ class NeutronAgent(abc.ABC):
def update(self, chassis_private, updated_at=None, clear_down=False):
self.chassis_private = chassis_private
self.updated_at = updated_at or timeutils.utcnow(with_timezone=True)
if not updated_at:
# When use the Chassis_Private table for agents health check,
# chassis_private has attribute nb_cfg_timestamp.
# nb_cfg_timestamp: the timestamp when ovn-controller finishes
# processing the change corresponding to nb_cfg(
# https://www.ovn.org/support/dist-docs/ovn-sb.5.html).
# it can better reflect the status of chassis.
# nb_cfg_timestamp is milliseconds, need to convert to datetime.
if hasattr(chassis_private, 'nb_cfg_timestamp'):
updated_at = datetime.datetime.fromtimestamp(
chassis_private.nb_cfg_timestamp / 1000,
datetime.timezone.utc)
else:
updated_at = timeutils.utcnow(with_timezone=True)
self.updated_at = updated_at
if clear_down:
self.set_down = False

View File

@ -29,6 +29,7 @@ from oslo_config import cfg
from oslo_db import exception as os_db_exc
from oslo_db.sqlalchemy import provision
from oslo_log import log
from oslo_utils import timeutils
from oslo_utils import uuidutils
from neutron.agent.linux import utils
@ -439,9 +440,11 @@ class TestOVNFunctionalBase(test_plugin.Ml2PluginV2TestCase,
name, ['geneve'], '172.24.4.%d' % self._counter,
external_ids=external_ids, hostname=host).execute(check_error=True)
if self.sb_api.is_table_present('Chassis_Private'):
nb_cfg_timestamp = timeutils.utcnow_ts() * 1000
self.sb_api.db_create(
'Chassis_Private', name=name, external_ids=external_ids,
chassis=chassis.uuid).execute(check_error=True)
chassis=chassis.uuid, nb_cfg_timestamp=nb_cfg_timestamp
).execute(check_error=True)
return name
def del_fake_chassis(self, chassis, if_exists=True):

View File

@ -11,7 +11,7 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import datetime
import functools
from unittest import mock
@ -22,6 +22,7 @@ from neutron_lib.api.definitions import portbindings
from neutron_lib.plugins import constants as plugin_constants
from neutron_lib.plugins import directory
from oslo_concurrency import processutils
from oslo_utils import timeutils
from oslo_utils import uuidutils
from ovsdbapp.backend.ovs_idl import event
from ovsdbapp.backend.ovs_idl import idlutils
@ -461,6 +462,21 @@ class TestAgentMonitor(base.TestOVNFunctionalBase):
self.assertEqual(neutron_agent.ControllerAgent,
type(neutron_agent.AgentCache()[self.chassis_name]))
def test_agent_updated_at_use_nb_cfg_timestamp(self):
if not self.sb_api.is_table_present('Chassis_Private'):
self.skipTest('Ovn sb not support Chassis_Private')
timestamp = timeutils.utcnow_ts()
nb_cfg_timestamp = timestamp * 1000
updated_at = datetime.datetime.fromtimestamp(
timestamp, datetime.timezone.utc)
self.sb_api.db_set('Chassis_Private', self.chassis_name, (
'nb_cfg_timestamp', nb_cfg_timestamp)).execute(check_error=True)
n_utils.wait_until_true(lambda:
neutron_agent.AgentCache()[self.chassis_name].
chassis_private.nb_cfg_timestamp == nb_cfg_timestamp)
agent = neutron_agent.AgentCache()[self.chassis_name]
self.assertEqual(updated_at, agent.updated_at)
class TestOvnIdlProbeInterval(base.TestOVNFunctionalBase):
def setUp(self):

View File

@ -2056,9 +2056,11 @@ class TestOVNMechanismDriver(TestOVNMechanismDriverBase):
updated_at=None):
updated_at = updated_at or timeutils.utcnow(with_timezone=True)
chassis_private = chassis_private or self._add_chassis(nb_cfg)
chassis_private.external_ids = {
ovn_const.OVN_LIVENESS_CHECK_EXT_ID_KEY:
datetime.datetime.isoformat(updated_at)}
if hasattr(chassis_private, 'nb_cfg_timestamp') and isinstance(
chassis_private.nb_cfg_timestamp, mock.Mock):
del chassis_private.nb_cfg_timestamp
chassis_private.external_ids = {}
if agent_type == ovn_const.OVN_METADATA_AGENT:
chassis_private.external_ids.update({
ovn_const.OVN_AGENT_METADATA_SB_CFG_KEY: nb_cfg,
@ -2115,6 +2117,35 @@ class TestOVNMechanismDriver(TestOVNMechanismDriverBase):
self.assertFalse(agent.alive, "Agent of type %s alive=%s" %
(agent.agent_type, agent.alive))
def test_agent_with_nb_cfg_timestamp_timeout(self):
nb_cfg = 3
chassis_private = self._add_chassis(nb_cfg)
self.mech_driver.nb_ovn.nb_global.nb_cfg = nb_cfg + 2
updated_at = (timeutils.utcnow_ts() - cfg.CONF.agent_down_time - 1
) * 1000
chassis_private.nb_cfg_timestamp = updated_at
agent_type = ovn_const.OVN_CONTROLLER_AGENT
updated_at = (timeutils.utcnow(with_timezone=True) -
datetime.timedelta(minutes=10))
agent = self._add_chassis_agent(nb_cfg, agent_type, chassis_private,
updated_at=updated_at)
self.assertFalse(agent.alive, "Agent of type %s alive=%s" %
(agent.agent_type, agent.alive))
def test_agent_with_nb_cfg_timestamp_not_timeout(self):
nb_cfg = 3
chassis_private = self._add_chassis(nb_cfg)
self.mech_driver.nb_ovn.nb_global.nb_cfg = nb_cfg + 2
updated_at = timeutils.utcnow_ts() * 1000
chassis_private.nb_cfg_timestamp = updated_at
agent_type = ovn_const.OVN_CONTROLLER_AGENT
agent = self._add_chassis_agent(nb_cfg, agent_type,
chassis_private)
self.assertTrue(agent.alive, "Agent of type %s alive=%s" % (
agent.agent_type, agent.alive))
def _test__update_dnat_entry_if_needed(self, up=True):
ovn_conf.cfg.CONF.set_override(
'enable_distributed_floating_ip', True, group='ovn')