1
# Copyright 2013 Canonical Ltd. This software is licensed under the
2
# GNU Affero General Public License version 3 (see the file LICENSE).
4
"""Tests for the :class:`DHCPLease` model."""
6
from __future__ import (
15
from maasserver import dns
16
from maasserver.models import DHCPLease
17
from maasserver.testing.factory import factory
18
from maasserver.testing.testcase import TestCase
19
from maasserver.utils import ignore_unused
22
def get_leases(nodegroup):
23
"""Return DHCPLease records for `nodegroup`."""
24
return DHCPLease.objects.filter(nodegroup=nodegroup)
27
def map_leases(nodegroup):
28
"""Return IP/MAC mappings dict for leases in `nodegroup`."""
29
return {lease.ip: lease.mac for lease in get_leases(nodegroup)}
32
class TestDHCPLease(TestCase):
33
"""Tests for :class:`DHCPLease`."""
36
nodegroup = factory.make_node_group()
37
ip = factory.getRandomIPAddress()
38
mac = factory.getRandomMACAddress()
40
lease = DHCPLease(nodegroup=nodegroup, ip=ip, mac=mac)
43
self.assertItemsEqual([lease], get_leases(nodegroup))
44
self.assertEqual(nodegroup, lease.nodegroup)
45
self.assertEqual(ip, lease.ip)
46
self.assertEqual(mac, lease.mac)
49
class TestDHCPLeaseManager(TestCase):
50
"""Tests for :class:`DHCPLeaseManager`."""
52
def test_update_leases_accepts_empty_leases(self):
53
nodegroup = factory.make_node_group()
54
DHCPLease.objects.update_leases(nodegroup, {})
55
self.assertItemsEqual([], get_leases(nodegroup))
57
def test_update_leases_creates_new_lease(self):
58
nodegroup = factory.make_node_group()
59
lease = factory.make_random_leases()
60
DHCPLease.objects.update_leases(nodegroup, lease)
61
self.assertEqual(lease, map_leases(nodegroup))
63
def test_update_leases_returns_new_leases(self):
64
nodegroup = factory.make_node_group()
65
obsolete_lease = factory.make_dhcp_lease(nodegroup=nodegroup)
66
ignore_unused(obsolete_lease)
67
remaining_lease = factory.make_dhcp_lease(nodegroup=nodegroup)
68
new_lease = factory.make_random_leases()
71
remaining_lease.ip: remaining_lease.mac,
72
new_lease.keys()[0]: new_lease.values()[0],
75
self.assertItemsEqual(
77
DHCPLease.objects.update_leases(nodegroup, surviving_leases))
79
def test_update_leases_deletes_obsolete_lease(self):
80
nodegroup = factory.make_node_group()
81
factory.make_dhcp_lease(nodegroup=nodegroup)
82
DHCPLease.objects.update_leases(nodegroup, {})
83
self.assertItemsEqual([], get_leases(nodegroup))
85
def test_update_leases_replaces_reassigned_ip(self):
86
nodegroup = factory.make_node_group()
87
ip = factory.getRandomIPAddress()
88
factory.make_dhcp_lease(nodegroup=nodegroup, ip=ip)
89
new_mac = factory.getRandomMACAddress()
90
DHCPLease.objects.update_leases(nodegroup, {ip: new_mac})
91
self.assertEqual({ip: new_mac}, map_leases(nodegroup))
93
def test_update_leases_keeps_unchanged_mappings(self):
94
original_lease = factory.make_dhcp_lease()
95
nodegroup = original_lease.nodegroup
96
DHCPLease.objects.update_leases(
97
nodegroup, {original_lease.ip: original_lease.mac})
98
self.assertItemsEqual([original_lease], get_leases(nodegroup))
100
def test_update_leases_adds_new_ip_to_mac(self):
101
nodegroup = factory.make_node_group()
102
mac = factory.getRandomMACAddress()
103
ip1 = factory.getRandomIPAddress()
104
ip2 = factory.getRandomIPAddress()
105
factory.make_dhcp_lease(nodegroup=nodegroup, mac=mac, ip=ip1)
106
DHCPLease.objects.update_leases(nodegroup, {ip1: mac, ip2: mac})
107
self.assertEqual({ip1: mac, ip2: mac}, map_leases(nodegroup))
109
def test_update_leases_deletes_only_obsolete_ips(self):
110
nodegroup = factory.make_node_group()
111
mac = factory.getRandomMACAddress()
112
obsolete_ip = factory.getRandomIPAddress()
113
current_ip = factory.getRandomIPAddress()
114
factory.make_dhcp_lease(nodegroup=nodegroup, mac=mac, ip=obsolete_ip)
115
factory.make_dhcp_lease(nodegroup=nodegroup, mac=mac, ip=current_ip)
116
DHCPLease.objects.update_leases(nodegroup, {current_ip: mac})
117
self.assertEqual({current_ip: mac}, map_leases(nodegroup))
119
def test_update_leases_leaves_other_nodegroups_alone(self):
120
innocent_nodegroup = factory.make_node_group()
121
innocent_lease = factory.make_dhcp_lease(nodegroup=innocent_nodegroup)
122
DHCPLease.objects.update_leases(
123
factory.make_node_group(), factory.make_random_leases())
124
self.assertItemsEqual(
125
[innocent_lease], get_leases(innocent_nodegroup))
127
def test_update_leases_combines_additions_deletions_and_replacements(self):
128
nodegroup = factory.make_node_group()
129
mac1 = factory.getRandomMACAddress()
130
mac2 = factory.getRandomMACAddress()
131
obsolete_lease = factory.make_dhcp_lease(
132
nodegroup=nodegroup, mac=mac1)
133
# The obsolete lease won't be in the update, so it'll disappear.
134
ignore_unused(obsolete_lease)
135
unchanged_lease = factory.make_dhcp_lease(
136
nodegroup=nodegroup, mac=mac1)
137
reassigned_lease = factory.make_dhcp_lease(
138
nodegroup=nodegroup, mac=mac1)
139
new_ip = factory.getRandomIPAddress()
140
DHCPLease.objects.update_leases(nodegroup, {
141
reassigned_lease.ip: mac2,
142
unchanged_lease.ip: mac1,
147
reassigned_lease.ip: mac2,
148
unchanged_lease.ip: mac1,
151
map_leases(nodegroup))
153
def test_update_leases_updates_dns_zone(self):
154
self.patch(dns, 'change_dns_zones')
155
nodegroup = factory.make_node_group()
156
DHCPLease.objects.update_leases(
157
nodegroup, factory.make_random_leases())
158
dns.change_dns_zones.assert_called_once_with([nodegroup])
160
def test_update_leases_does_not_update_dns_zone_if_nothing_added(self):
161
self.patch(dns, 'change_dns_zones')
162
nodegroup = factory.make_node_group()
163
DHCPLease.objects.update_leases(nodegroup, {})
164
self.assertFalse(dns.change_dns_zones.called)
166
def test_get_hostname_ip_mapping_returns_mapping(self):
167
nodegroup = factory.make_node_group()
168
expected_mapping = {}
170
node = factory.make_node(
172
mac = factory.make_mac_address(node=node)
173
factory.make_mac_address(node=node)
174
lease = factory.make_dhcp_lease(
175
nodegroup=nodegroup, mac=mac.mac_address)
176
expected_mapping[node.hostname] = lease.ip
177
mapping = DHCPLease.objects.get_hostname_ip_mapping(nodegroup)
178
self.assertEqual(expected_mapping, mapping)
180
def test_get_hostname_ip_mapping_strips_out_domain(self):
181
nodegroup = factory.make_node_group()
182
hostname = factory.make_name('hostname')
183
domain = factory.make_name('domain')
184
node = factory.make_node(
186
hostname='%s.%s' % (hostname, domain))
187
mac = factory.make_mac_address(node=node)
188
lease = factory.make_dhcp_lease(
189
nodegroup=nodegroup, mac=mac.mac_address)
190
mapping = DHCPLease.objects.get_hostname_ip_mapping(nodegroup)
191
self.assertEqual({hostname: lease.ip}, mapping)
193
def test_get_hostname_ip_mapping_picks_mac_with_lease(self):
194
node = factory.make_node(hostname=factory.make_name('host'))
195
factory.make_mac_address(node=node)
196
second_mac = factory.make_mac_address(node=node)
197
# Create a lease for the second MAC Address.
198
lease = factory.make_dhcp_lease(
199
nodegroup=node.nodegroup, mac=second_mac.mac_address)
200
mapping = DHCPLease.objects.get_hostname_ip_mapping(node.nodegroup)
201
self.assertEqual({node.hostname: lease.ip}, mapping)
203
def test_get_hostname_ip_mapping_picks_oldest_mac_with_lease(self):
204
node = factory.make_node(hostname=factory.make_name('host'))
205
older_mac = factory.make_mac_address(node=node)
206
newer_mac = factory.make_mac_address(node=node)
208
factory.make_dhcp_lease(
209
nodegroup=node.nodegroup, mac=newer_mac.mac_address)
210
lease_for_older_mac = factory.make_dhcp_lease(
211
nodegroup=node.nodegroup, mac=older_mac.mac_address)
213
mapping = DHCPLease.objects.get_hostname_ip_mapping(node.nodegroup)
214
self.assertEqual({node.hostname: lease_for_older_mac.ip}, mapping)
216
def test_get_hostname_ip_mapping_considers_given_nodegroup(self):
217
nodegroup = factory.make_node_group()
218
node = factory.make_node(
220
mac = factory.make_mac_address(node=node)
221
factory.make_dhcp_lease(
222
nodegroup=nodegroup, mac=mac.mac_address)
223
another_nodegroup = factory.make_node_group()
224
mapping = DHCPLease.objects.get_hostname_ip_mapping(
226
self.assertEqual({}, mapping)