Merge ~ack/maas:1902425-again-2.9 into maas:2.9

Proposed by Alberto Donato
Status: Merged
Approved by: Alberto Donato
Approved revision: 7e2efe7305ffa8ad446f87b8d2410d246d8e2644
Merge reported by: MAAS Lander
Merged at revision: not available
Proposed branch: ~ack/maas:1902425-again-2.9
Merge into: maas:2.9
Diff against target: 435 lines (+159/-64)
4 files modified
src/maasserver/models/interface.py (+7/-20)
src/maasserver/models/node.py (+15/-8)
src/maasserver/models/tests/test_interface.py (+12/-22)
src/maasserver/models/tests/test_node.py (+125/-14)
Reviewer Review Type Date Requested Status
MAAS Lander Approve
Alberto Donato (community) Approve
Review via email: mp+398150@code.launchpad.net

Commit message

LP: #1902425

 - always create neighbour entries for IPs in use.
 - exclude already tested IPs when claiming IPs during deploy

Rework Interface.update_neighbour move check for neighbour discovery to call sites.
This also changes IP claim checks to always create a neighbour entry when the IP is found to be in use (even if the rack interface doesn't have neighbour discovery enabled).

This fixes a corner case for the linked bug which happens when the used IP is
on an interface that has neighbour discovery disabled, in which case the IP is
not recorded in MAAS, and can get picked up again.

To post a comment you must log in.
Revision history for this message
Alberto Donato (ack) :
review: Approve
Revision history for this message
MAAS Lander (maas-lander) wrote :
Revision history for this message
MAAS Lander (maas-lander) wrote :
Revision history for this message
MAAS Lander (maas-lander) wrote :

UNIT TESTS
-b 1902425-again-2.9 lp:~ack/maas/+git/maas into -b 2.9 lp:~maas-committers/maas

STATUS: SUCCESS
COMMIT: 7e2efe7305ffa8ad446f87b8d2410d246d8e2644

review: Approve

There was an error fetching revisions from git servers. Please try again in a few minutes. If the problem persists, contact Launchpad support.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/src/maasserver/models/interface.py b/src/maasserver/models/interface.py
index b7738dc..b5d9625 100644
--- a/src/maasserver/models/interface.py
+++ b/src/maasserver/models/interface.py
@@ -111,7 +111,7 @@ class InterfaceQueriesMixin(MAASQueriesMixin):
111 specifiers,111 specifiers,
112 specifier_types=specifier_types,112 specifier_types=specifier_types,
113 separator=separator,113 separator=separator,
114 **kwargs114 **kwargs,
115 )115 )
116116
117 def _add_interface_id_query(self, current_q, op, item):117 def _add_interface_id_query(self, current_q, op, item):
@@ -1522,20 +1522,10 @@ class Interface(CleanSave, TimestampedModel):
1522 % (self.get_log_string(), vid, vlan.fabric.get_name())1522 % (self.get_log_string(), vid, vlan.fabric.get_name())
1523 )1523 )
15241524
1525 def update_neighbour(self, neighbour_json: dict):1525 def update_neighbour(self, ip, mac, time, vid=None):
1526 """Updates the neighbour table for this interface.1526 """Updates the neighbour table for this interface."""
1527
1528 Input is expected to be the neighbour JSON from the controller.
1529 """
1530 # Circular imports
1531 from maasserver.models.neighbour import Neighbour1527 from maasserver.models.neighbour import Neighbour
15321528
1533 if self.neighbour_discovery_state is False:
1534 return None
1535 ip = neighbour_json["ip"]
1536 mac = neighbour_json["mac"]
1537 time = neighbour_json["time"]
1538 vid = neighbour_json.get("vid", None)
1539 deleted = Neighbour.objects.delete_and_log_obsolete_neighbours(1529 deleted = Neighbour.objects.delete_and_log_obsolete_neighbours(
1540 ip, mac, interface=self, vid=vid1530 ip, mac, interface=self, vid=vid
1541 )1531 )
@@ -1552,13 +1542,10 @@ class Interface(CleanSave, TimestampedModel):
1552 # generated a log statement about this neighbour.1542 # generated a log statement about this neighbour.
1553 if not deleted:1543 if not deleted:
1554 maaslog.info(1544 maaslog.info(
1555 "%s: New MAC, IP binding observed%s: %s, %s"1545 f"{self.get_log_string()}: "
1556 % (1546 "New MAC, IP binding "
1557 self.get_log_string(),1547 f"observed{Neighbour.objects.get_vid_log_snippet(vid)}: "
1558 Neighbour.objects.get_vid_log_snippet(vid),1548 f"{mac}, {ip}"
1559 mac,
1560 ip,
1561 )
1562 )1549 )
1563 else:1550 else:
1564 neighbour.time = time1551 neighbour.time = time
diff --git a/src/maasserver/models/node.py b/src/maasserver/models/node.py
index 5d506b4..48852de 100644
--- a/src/maasserver/models/node.py
+++ b/src/maasserver/models/node.py
@@ -4337,9 +4337,11 @@ class Node(CleanSave, TimestampedModel):
4337 bridge_fd=bridge_fd,4337 bridge_fd=bridge_fd,
4338 )4338 )
43394339
4340 def claim_auto_ips(self, temp_expires_after=None):4340 def claim_auto_ips(self, exclude_addresses=None, temp_expires_after=None):
4341 """Assign IP addresses to all interface links set to AUTO."""4341 """Assign IP addresses to all interface links set to AUTO."""
4342 exclude_addresses = set()4342 exclude_addresses = (
4343 exclude_addresses.copy() if exclude_addresses else set()
4344 )
4343 allocated_ips = set()4345 allocated_ips = set()
4344 # Query for the interfaces again here; if we use the cached4346 # Query for the interfaces again here; if we use the cached
4345 # interface_set, we could skip a newly-created bridge if it was created4347 # interface_set, we could skip a newly-created bridge if it was created
@@ -4480,11 +4482,9 @@ class Node(CleanSave, TimestampedModel):
4480 rack_interface = rack_interface.order_by("id")4482 rack_interface = rack_interface.order_by("id")
4481 rack_interface = rack_interface.first()4483 rack_interface = rack_interface.first()
4482 rack_interface.update_neighbour(4484 rack_interface.update_neighbour(
4483 {4485 ip_obj.ip,
4484 "ip": ip_obj.ip,4486 ip_result.get("mac_address"),
4485 "mac": ip_result.get("mac_address"),4487 time.time(),
4486 "time": time.time(),
4487 }
4488 )4488 )
4489 ip_obj.ip = None4489 ip_obj.ip = None
4490 ip_obj.temp_expires_on = None4490 ip_obj.temp_expires_on = None
@@ -4502,6 +4502,7 @@ class Node(CleanSave, TimestampedModel):
4502 yield deferToDatabase(clean_expired)4502 yield deferToDatabase(clean_expired)
4503 allocated_ips = yield deferToDatabase(4503 allocated_ips = yield deferToDatabase(
4504 transactional(self.claim_auto_ips),4504 transactional(self.claim_auto_ips),
4505 exclude_addresses=attempted_ips,
4505 temp_expires_after=timedelta(minutes=5),4506 temp_expires_after=timedelta(minutes=5),
4506 )4507 )
4507 if not allocated_ips:4508 if not allocated_ips:
@@ -6723,8 +6724,14 @@ class Controller(Node):
6723 for neighbour in neighbours:6724 for neighbour in neighbours:
6724 interface = interfaces.get(neighbour["interface"], None)6725 interface = interfaces.get(neighbour["interface"], None)
6725 if interface is not None:6726 if interface is not None:
6726 interface.update_neighbour(neighbour)
6727 vid = neighbour.get("vid", None)6727 vid = neighbour.get("vid", None)
6728 if interface.neighbour_discovery_state:
6729 interface.update_neighbour(
6730 neighbour["ip"],
6731 neighbour["mac"],
6732 neighbour["time"],
6733 vid=vid,
6734 )
6728 if vid is not None:6735 if vid is not None:
6729 interface.report_vid(vid)6736 interface.report_vid(vid)
67306737
diff --git a/src/maasserver/models/tests/test_interface.py b/src/maasserver/models/tests/test_interface.py
index b86dbfb..ee16f56 100644
--- a/src/maasserver/models/tests/test_interface.py
+++ b/src/maasserver/models/tests/test_interface.py
@@ -1363,7 +1363,7 @@ class InterfaceTest(MAASServerTestCase):
1363 self.assertEquals(0, interface.link_speed)1363 self.assertEquals(0, interface.link_speed)
13641364
13651365
1366class InterfaceUpdateNeighbourTest(MAASServerTestCase):1366class TestInterfaceUpdateNeighbour(MAASServerTestCase):
1367 """Tests for `Interface.update_neighbour`."""1367 """Tests for `Interface.update_neighbour`."""
13681368
1369 def make_neighbour_json(self, ip=None, mac=None, time=None, **kwargs):1369 def make_neighbour_json(self, ip=None, mac=None, time=None, **kwargs):
@@ -1384,22 +1384,15 @@ class InterfaceUpdateNeighbourTest(MAASServerTestCase):
1384 vid = None1384 vid = None
1385 return {"ip": ip, "mac": mac, "time": time, "vid": vid}1385 return {"ip": ip, "mac": mac, "time": time, "vid": vid}
13861386
1387 def test_ignores_updates_if_neighbour_discovery_state_is_false(self):1387 def test_adds_new_neighbour(self):
1388 iface = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)1388 iface = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)
1389 iface.update_neighbour(self.make_neighbour_json())1389 iface.update_neighbour(**self.make_neighbour_json())
1390 self.assertThat(Neighbour.objects.count(), Equals(0))
1391
1392 def test_adds_new_neighbour_if_neighbour_discovery_state_is_true(self):
1393 iface = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)
1394 iface.neighbour_discovery_state = True
1395 iface.update_neighbour(self.make_neighbour_json())
1396 self.assertThat(Neighbour.objects.count(), Equals(1))1390 self.assertThat(Neighbour.objects.count(), Equals(1))
13971391
1398 def test_updates_existing_neighbour(self):1392 def test_updates_existing_neighbour(self):
1399 iface = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)1393 iface = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)
1400 iface.neighbour_discovery_state = True
1401 json = self.make_neighbour_json()1394 json = self.make_neighbour_json()
1402 iface.update_neighbour(json)1395 iface.update_neighbour(**json)
1403 neighbour = get_one(Neighbour.objects.all())1396 neighbour = get_one(Neighbour.objects.all())
1404 # Pretend this was updated one day ago.1397 # Pretend this was updated one day ago.
1405 yesterday = datetime.datetime.now() - datetime.timedelta(days=1)1398 yesterday = datetime.datetime.now() - datetime.timedelta(days=1)
@@ -1410,7 +1403,7 @@ class InterfaceUpdateNeighbourTest(MAASServerTestCase):
1410 Equals(int(yesterday.timestamp())),1403 Equals(int(yesterday.timestamp())),
1411 )1404 )
1412 json["time"] += 11405 json["time"] += 1
1413 iface.update_neighbour(json)1406 iface.update_neighbour(**json)
1414 neighbour = reload_object(neighbour)1407 neighbour = reload_object(neighbour)
1415 self.assertThat(Neighbour.objects.count(), Equals(1))1408 self.assertThat(Neighbour.objects.count(), Equals(1))
1416 self.assertThat(neighbour.time, Equals(json["time"]))1409 self.assertThat(neighbour.time, Equals(json["time"]))
@@ -1422,13 +1415,12 @@ class InterfaceUpdateNeighbourTest(MAASServerTestCase):
14221415
1423 def test_replaces_obsolete_neighbour(self):1416 def test_replaces_obsolete_neighbour(self):
1424 iface = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)1417 iface = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)
1425 iface.neighbour_discovery_state = True
1426 json = self.make_neighbour_json()1418 json = self.make_neighbour_json()
1427 iface.update_neighbour(json)1419 iface.update_neighbour(**json)
1428 # Have a different MAC address claim ownership of the IP.1420 # Have a different MAC address claim ownership of the IP.
1429 json["time"] += 11421 json["time"] += 1
1430 json["mac"] = factory.make_mac_address()1422 json["mac"] = factory.make_mac_address()
1431 iface.update_neighbour(json)1423 iface.update_neighbour(**json)
1432 self.assertThat(Neighbour.objects.count(), Equals(1))1424 self.assertThat(Neighbour.objects.count(), Equals(1))
1433 self.assertThat(1425 self.assertThat(
1434 list(Neighbour.objects.all())[0].mac_address, Equals(json["mac"])1426 list(Neighbour.objects.all())[0].mac_address, Equals(json["mac"])
@@ -1439,10 +1431,8 @@ class InterfaceUpdateNeighbourTest(MAASServerTestCase):
14391431
1440 def test_logs_new_binding(self):1432 def test_logs_new_binding(self):
1441 iface = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)1433 iface = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)
1442 iface.neighbour_discovery_state = True
1443 json = self.make_neighbour_json()
1444 with FakeLogger("maas.interface") as maaslog:1434 with FakeLogger("maas.interface") as maaslog:
1445 iface.update_neighbour(json)1435 iface.update_neighbour(**self.make_neighbour_json())
1446 self.assertDocTestMatches(1436 self.assertDocTestMatches(
1447 "...: New MAC, IP binding observed...", maaslog.output1437 "...: New MAC, IP binding observed...", maaslog.output
1448 )1438 )
@@ -1451,18 +1441,18 @@ class InterfaceUpdateNeighbourTest(MAASServerTestCase):
1451 iface = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)1441 iface = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)
1452 iface.neighbour_discovery_state = True1442 iface.neighbour_discovery_state = True
1453 json = self.make_neighbour_json()1443 json = self.make_neighbour_json()
1454 iface.update_neighbour(json)1444 iface.update_neighbour(**json)
1455 # Have a different MAC address claim ownership of the IP.1445 # Have a different MAC address claim ownership of the IP.
1456 json["time"] += 11446 json["time"] += 1
1457 json["mac"] = factory.make_mac_address()1447 json["mac"] = factory.make_mac_address()
1458 with FakeLogger("maas.neighbour") as maaslog:1448 with FakeLogger("maas.neighbour") as maaslog:
1459 iface.update_neighbour(json)1449 iface.update_neighbour(**json)
1460 self.assertDocTestMatches(1450 self.assertDocTestMatches(
1461 "...: IP address...moved from...to...", maaslog.output1451 "...: IP address...moved from...to...", maaslog.output
1462 )1452 )
14631453
14641454
1465class InterfaceUpdateMDNSEntryTest(MAASServerTestCase):1455class TestInterfaceUpdateMDNSEntry(MAASServerTestCase):
1466 """Tests for `Interface.update_mdns_entry`."""1456 """Tests for `Interface.update_mdns_entry`."""
14671457
1468 def make_mdns_entry_json(self, ip=None, hostname=None):1458 def make_mdns_entry_json(self, ip=None, hostname=None):
@@ -1477,7 +1467,7 @@ class InterfaceUpdateMDNSEntryTest(MAASServerTestCase):
14771467
1478 def test_ignores_updates_if_mdns_discovery_state_is_false(self):1468 def test_ignores_updates_if_mdns_discovery_state_is_false(self):
1479 iface = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)1469 iface = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)
1480 iface.update_neighbour(self.make_mdns_entry_json())1470 iface.update_mdns_entry(self.make_mdns_entry_json())
1481 self.assertThat(MDNS.objects.count(), Equals(0))1471 self.assertThat(MDNS.objects.count(), Equals(0))
14821472
1483 def test_adds_new_entry_if_mdns_discovery_state_is_true(self):1473 def test_adds_new_entry_if_mdns_discovery_state_is_true(self):
diff --git a/src/maasserver/models/tests/test_node.py b/src/maasserver/models/tests/test_node.py
index a5a5aa7..61f1fe6 100644
--- a/src/maasserver/models/tests/test_node.py
+++ b/src/maasserver/models/tests/test_node.py
@@ -79,6 +79,7 @@ from maasserver.exceptions import (
79 StaticIPAddressExhaustion,79 StaticIPAddressExhaustion,
80)80)
81from maasserver.models import (81from maasserver.models import (
82 BMCRoutableRackControllerRelationship,
82 BondInterface,83 BondInterface,
83 BootResource,84 BootResource,
84 BridgeInterface,85 BridgeInterface,
@@ -86,11 +87,13 @@ from maasserver.models import (
86 Controller,87 Controller,
87 Device,88 Device,
88 Domain,89 Domain,
90 Event,
89 EventType,91 EventType,
90 Fabric,92 Fabric,
91 Interface,93 Interface,
92 LicenseKey,94 LicenseKey,
93 Machine,95 Machine,
96 Neighbour,
94 Node,97 Node,
95)98)
96from maasserver.models import (99from maasserver.models import (
@@ -100,6 +103,7 @@ from maasserver.models import (
100 RAID,103 RAID,
101 RegionController,104 RegionController,
102 RegionRackRPCConnection,105 RegionRackRPCConnection,
106 ResourcePool,
103 Service,107 Service,
104 StaticIPAddress,108 StaticIPAddress,
105 Subnet,109 Subnet,
@@ -108,12 +112,10 @@ from maasserver.models import (
108 VLANInterface,112 VLANInterface,
109 VolumeGroup,113 VolumeGroup,
110)114)
111from maasserver.models import Bcache115from maasserver.models import Bcache, BMC
112from maasserver.models import bmc as bmc_module116from maasserver.models import bmc as bmc_module
113from maasserver.models import node as node_module117from maasserver.models import node as node_module
114from maasserver.models.bmc import BMC, BMCRoutableRackControllerRelationship
115from maasserver.models.config import NetworkDiscoveryConfig118from maasserver.models.config import NetworkDiscoveryConfig
116from maasserver.models.event import Event
117import maasserver.models.interface as interface_module119import maasserver.models.interface as interface_module
118from maasserver.models.node import (120from maasserver.models.node import (
119 DEFAULT_BIOS_BOOT_METHOD,121 DEFAULT_BIOS_BOOT_METHOD,
@@ -123,7 +125,6 @@ from maasserver.models.node import (
123 PowerInfo,125 PowerInfo,
124)126)
125from maasserver.models.partitiontable import PARTITION_TABLE_EXTRA_SPACE127from maasserver.models.partitiontable import PARTITION_TABLE_EXTRA_SPACE
126from maasserver.models.resourcepool import ResourcePool
127from maasserver.models.signals import power as node_query128from maasserver.models.signals import power as node_query
128from maasserver.models.timestampedmodel import now129from maasserver.models.timestampedmodel import now
129from maasserver.node_status import (130from maasserver.node_status import (
@@ -8694,6 +8695,74 @@ class TestNode_Start(MAASTransactionServerTestCase):
8694 self.assertThat(auto_ip.ip, Equals(third_ip.ip))8695 self.assertThat(auto_ip.ip, Equals(third_ip.ip))
8695 self.assertThat(auto_ip.temp_expires_on, Is(None))8696 self.assertThat(auto_ip.temp_expires_on, Is(None))
86968697
8698 def test_claims_auto_ip_addresses_skips_used_ip_discovery_disabled(self):
8699 user = factory.make_User()
8700 node = self.make_acquired_node_with_interface(
8701 user, power_type="manual"
8702 )
8703 node_interface = node.get_boot_interface()
8704 [auto_ip] = node_interface.ip_addresses.filter(
8705 alloc_type=IPADDRESS_TYPE.AUTO
8706 )
8707
8708 # Create a rack controller that has an interface on the same subnet
8709 # as the node. Don't enable neighbour discovery
8710 rack = factory.make_RackController()
8711 rack.interface_set.all().delete()
8712 rackif = factory.make_Interface(vlan=node_interface.vlan, node=rack)
8713 rackif_ip = factory.pick_ip_in_Subnet(auto_ip.subnet)
8714 rackif.link_subnet(
8715 INTERFACE_LINK_TYPE.STATIC, auto_ip.subnet, rackif_ip
8716 )
8717
8718 # Mock the rack controller connected to the region controller.
8719 client = Mock()
8720 client.ident = rack.system_id
8721 self.patch(node_module, "getAllClients").return_value = [client]
8722
8723 # Must be executed in a transaction as `allocate_new` uses savepoints.
8724 with transaction.atomic():
8725 # Get two IPs and remove them so they're unknown
8726 ip = StaticIPAddress.objects.allocate_new(
8727 subnet=auto_ip.subnet, alloc_type=IPADDRESS_TYPE.AUTO
8728 )
8729 ip1 = ip.ip
8730 ip.delete()
8731 ip = StaticIPAddress.objects.allocate_new(
8732 subnet=auto_ip.subnet,
8733 alloc_type=IPADDRESS_TYPE.AUTO,
8734 exclude_addresses=[ip1],
8735 )
8736 ip2 = ip.ip
8737 ip.delete()
8738
8739 client.side_effect = [
8740 defer.succeed(
8741 {
8742 "ip_addresses": [
8743 {
8744 "ip_address": ip1,
8745 "used": True,
8746 "mac_address": factory.make_mac_address(),
8747 }
8748 ]
8749 }
8750 ),
8751 defer.succeed(
8752 {"ip_addresses": [{"ip_address": ip2, "used": False}]}
8753 ),
8754 ]
8755
8756 with post_commit_hooks:
8757 node.start(user)
8758
8759 auto_ip = reload_object(auto_ip)
8760 self.assertThat(auto_ip.ip, Equals(ip2))
8761 self.assertThat(auto_ip.temp_expires_on, Is(None))
8762 self.assertCountEqual(
8763 [ip1], Neighbour.objects.values_list("ip", flat=True)
8764 )
8765
8697 def test_claims_auto_ip_addresses_retries_on_failure_from_rack(self):8766 def test_claims_auto_ip_addresses_retries_on_failure_from_rack(self):
8698 user = factory.make_User()8767 user = factory.make_User()
8699 node = self.make_acquired_node_with_interface(8768 node = self.make_acquired_node_with_interface(
@@ -9914,21 +9983,51 @@ class TestControllerUpdateDiscoveryState(MAASServerTestCase):
9914class TestReportNeighbours(MAASServerTestCase):9983class TestReportNeighbours(MAASServerTestCase):
9915 """Tests for `Controller.report_neighbours()."""9984 """Tests for `Controller.report_neighbours()."""
99169985
9917 def test_calls_update_neighbour_for_each_neighbour(self):9986 def test_no_update_neighbours_calls_if_discovery_disabled(self):
9918 rack = factory.make_RackController()9987 rack = factory.make_RackController()
9919 factory.make_Interface(name="eth0", node=rack)9988 factory.make_Interface(name="eth0", node=rack)
9920 factory.make_Interface(name="eth1", node=rack)
9921 update_neighbour = self.patch(9989 update_neighbour = self.patch(
9922 interface_module.Interface, "update_neighbour"9990 interface_module.Interface, "update_neighbour"
9923 )9991 )
9924 neighbours = [9992 neighbours = [
9925 {"interface": "eth0", "mac": factory.make_mac_address()},9993 {
9926 {"interface": "eth1", "mac": factory.make_mac_address()},9994 "interface": "eth0",
9995 "mac": factory.make_mac_address(),
9996 "ip": factory.make_ipv4_address(),
9997 "time": datetime.now(),
9998 },
9999 ]
10000 rack.report_neighbours(neighbours)
10001 update_neighbour.assert_not_called()
10002
10003 def test_calls_update_neighbour_for_each_neighbour(self):
10004 rack = factory.make_RackController()
10005 if1 = factory.make_Interface(name="eth0", node=rack)
10006 if1.neighbour_discovery_state = True
10007 if1.save()
10008 if2 = factory.make_Interface(name="eth1", node=rack)
10009 if2.neighbour_discovery_state = True
10010 if2.save()
10011 update_neighbour = self.patch(
10012 interface_module.Interface, "update_neighbour"
10013 )
10014 neighbours = [
10015 {
10016 "interface": "eth0",
10017 "mac": factory.make_mac_address(),
10018 "ip": factory.make_ipv4_address(),
10019 "time": datetime.now(),
10020 },
10021 {
10022 "interface": "eth1",
10023 "mac": factory.make_mac_address(),
10024 "ip": factory.make_ipv4_address(),
10025 "time": datetime.now(),
10026 },
9927 ]10027 ]
9928 rack.report_neighbours(neighbours)10028 rack.report_neighbours(neighbours)
9929 self.assertThat(10029 update_neighbour.assert_has_calls(
9930 update_neighbour,10030 [call(n["ip"], n["mac"], n["time"], vid=None) for n in neighbours]
9931 MockCallsMatch(*[call(neighbour) for neighbour in neighbours]),
9932 )10031 )
993310032
9934 def test_calls_report_vid_for_each_vid(self):10033 def test_calls_report_vid_for_each_vid(self):
@@ -9939,11 +10038,23 @@ class TestReportNeighbours(MAASServerTestCase):
9939 self.patch(interface_module.Interface, "update_neighbour")10038 self.patch(interface_module.Interface, "update_neighbour")
9940 report_vid = self.patch(interface_module.Interface, "report_vid")10039 report_vid = self.patch(interface_module.Interface, "report_vid")
9941 neighbours = [10040 neighbours = [
9942 {"interface": "eth0", "mac": factory.make_mac_address(), "vid": 3},10041 {
9943 {"interface": "eth1", "mac": factory.make_mac_address(), "vid": 7},10042 "interface": "eth0",
10043 "ip": factory.make_ipv4_address(),
10044 "time": datetime.now(),
10045 "mac": factory.make_mac_address(),
10046 "vid": 3,
10047 },
10048 {
10049 "interface": "eth1",
10050 "ip": factory.make_ipv4_address(),
10051 "time": datetime.now(),
10052 "mac": factory.make_mac_address(),
10053 "vid": 7,
10054 },
9944 ]10055 ]
9945 rack.report_neighbours(neighbours)10056 rack.report_neighbours(neighbours)
9946 self.assertThat(report_vid, MockCallsMatch(call(3), call(7)))10057 report_vid.assert_has_calls([call(3), call(7)])
994710058
994810059
9949class TestReportMDNSEntries(MAASServerTestCase):10060class TestReportMDNSEntries(MAASServerTestCase):

Subscribers

People subscribed via source and target branches