~lamont/maas/bug-1599223-2.0

« back to all changes in this revision

Viewing changes to src/maasserver/models/interface.py

  • Committer: Mike Pontillo
  • Date: 2015-12-04 20:10:02 UTC
  • mto: This revision was merged to the branch mainline in revision 4547.
  • Revision ID: mike.pontillo@canonical.com-20151204201002-1k3t8erytvtsy7tp
Merge revision 4520 from MAAS 1.9 (IP allocation fixes, bug #1519090, #1519077)

Show diffs side-by-side

added added

removed removed

Lines of Context:
52
52
    NODEGROUPINTERFACE_MANAGEMENT,
53
53
)
54
54
from maasserver.exceptions import (
 
55
    StaticIPAddressExhaustion,
55
56
    StaticIPAddressOutOfRange,
56
57
    StaticIPAddressUnavailable,
57
58
)
350
351
    def get_node(self):
351
352
        return self.node
352
353
 
 
354
    def get_log_string(self):
 
355
        hostname = "<unknown-node>"
 
356
        node = self.get_node()
 
357
        if node is not None:
 
358
            hostname = node.hostname
 
359
        return "%s on %s" % (self.get_name(), hostname)
 
360
 
353
361
    def get_name(self):
354
362
        return self.name
355
363
 
879
887
        be identified then its just set to DHCP.
880
888
        """
881
889
        found_subnet = None
 
890
        # XXX mpontillo 2015-11-29: since we tend to dump a large number of
 
891
        # subnets into the default VLAN, this assumption might be incorrect in
 
892
        # many cases, leading to interfaces being configured as AUTO when
 
893
        # they should be configured as DHCP.
882
894
        for subnet in self.vlan.subnet_set.all():
883
895
            ngi = subnet.get_managed_cluster_interface()
884
896
            if ngi is not None:
1109
1121
                    auto_ip, exclude_addresses)
1110
1122
                if ngi is not None:
1111
1123
                    affected_nodegroups.add(ngi.nodegroup)
1112
 
                assigned_addresses.append(assigned_ip)
1113
 
                exclude_addresses.add(unicode(assigned_ip.ip))
 
1124
                if assigned_ip is not None:
 
1125
                    assigned_addresses.append(assigned_ip)
 
1126
                    exclude_addresses.add(unicode(assigned_ip.ip))
1114
1127
        self._update_dns_zones(affected_nodegroups)
1115
1128
        return assigned_addresses
1116
1129
 
1117
1130
    def _claim_auto_ip(self, auto_ip, exclude_addresses=[]):
1118
 
        """Claim an IP address for the `auto_ip`."""
 
1131
        """Claim an IP address for the `auto_ip`.
 
1132
 
 
1133
        :returns:NodeGroupInterface, new_ip_address
 
1134
        """
1119
1135
        # Check if already has a hostmap allocated for this MAC address.
1120
1136
        subnet = auto_ip.subnet
 
1137
        if subnet is None:
 
1138
            maaslog.error(
 
1139
                "Could not find subnet for interface %s." %
 
1140
                (self.get_log_string()))
 
1141
            raise StaticIPAddressUnavailable(
 
1142
                "Automatic IP address cannot be configured on interface %s "
 
1143
                "without an associated subnet." % self.get_name())
 
1144
 
1121
1145
        ngi = subnet.get_managed_cluster_interface()
 
1146
        if ngi is None:
 
1147
            # Couldn't find a managed cluster interface for this node. So look
 
1148
            # for any interface (must be an UNMANAGED interface, since any
 
1149
            # managed NodeGroupInterface MUST have a Subnet link) whose
 
1150
            # static or dynamic range is within the given subnet.
 
1151
            ngi = NodeGroupInterface.objects.get_by_managed_range_for_subnet(
 
1152
                subnet)
 
1153
 
 
1154
        has_existing_mapping = False
 
1155
        has_static_range = False
 
1156
        has_dynamic_range = False
 
1157
 
1122
1158
        if ngi is not None:
1123
 
            has_allocations = self._has_static_allocation_on_cluster(
 
1159
            has_existing_mapping = self._has_static_allocation_on_cluster(
1124
1160
                ngi.nodegroup, get_subnet_family(subnet))
1125
 
        else:
1126
 
            has_allocations = False
1127
 
 
1128
 
        # Create a new AUTO IP.
1129
 
        if ngi is not None:
 
1161
            has_static_range = ngi.has_static_ip_range()
 
1162
            has_dynamic_range = ngi.has_dynamic_ip_range()
 
1163
 
 
1164
        if not has_static_range and has_dynamic_range:
 
1165
            # This means we found a matching NodeGroupInterface, but only its
 
1166
            # dynamic range is defined. Since a dynamic range is defined, that
 
1167
            # means this subnet is NOT managed by MAAS (or it's misconfigured),
 
1168
            # so we cannot just hand out a random IP address and risk a
 
1169
            # duplicate IP address.
 
1170
            maaslog.error(
 
1171
                "Found matching NodeGroupInterface, but no static range has "
 
1172
                "been defined for %s. (did you mean to configure DHCP?) " %
 
1173
                (self.get_log_string()))
 
1174
            raise StaticIPAddressUnavailable(
 
1175
                "Cluster interface for %s only has a dynamic range. Configure "
 
1176
                "a static range, or reconfigure the interface." %
 
1177
                (self.get_name()))
 
1178
 
 
1179
        if has_static_range:
 
1180
            # Allocate a new AUTO address from the static range.
1130
1181
            network = ngi.network
1131
1182
            static_ip_range_low = ngi.static_ip_range_low
1132
1183
            static_ip_range_high = ngi.static_ip_range_high
1133
1184
        else:
 
1185
            # We either found a NodeGroupInterface with no static or dynamic
 
1186
            # range, or we have a Subnet not associated with a
 
1187
            # NodeGroupInterface. This implies that it's okay to assign any
 
1188
            # unused IP address on the subnet.
1134
1189
            network = subnet.get_ipnetwork()
1135
1190
            static_ip_range_low, static_ip_range_high = (
1136
1191
                get_first_and_last_usable_host_in_network(network))
 
1192
        in_use_ipset = subnet.get_ipranges_in_use()
1137
1193
        new_ip = StaticIPAddress.objects.allocate_new(
1138
1194
            network, static_ip_range_low, static_ip_range_high,
1139
1195
            None, None, alloc_type=IPADDRESS_TYPE.AUTO,
1140
 
            subnet=subnet, exclude_addresses=exclude_addresses)
 
1196
            subnet=subnet, exclude_addresses=exclude_addresses,
 
1197
            in_use_ipset=in_use_ipset)
1141
1198
        self.ip_addresses.add(new_ip)
 
1199
        maaslog.info("Allocated automatic%s IP address %s for %s." % (
 
1200
            " static" if has_static_range else "", new_ip.ip,
 
1201
            self.get_log_string()))
1142
1202
 
1143
 
        # Update the hostmap for the new IP address if needed.
1144
 
        if ngi is not None and not has_allocations:
 
1203
        if ngi is not None and not has_existing_mapping:
 
1204
            # Update DHCP (if needed).
1145
1205
            self._update_host_maps(ngi.nodegroup, new_ip)
1146
1206
 
1147
 
        # Made it this far then the AUTO IP address has been assigned and the
1148
 
        # hostmap has been updated if needed. We can now remove the original
1149
 
        # empty AUTO IP address.
 
1207
        # If we made it this far, then the AUTO IP address has been assigned
 
1208
        # and the hostmap has been updated if needed. We can now remove the
 
1209
        # original empty AUTO IP address.
1150
1210
        auto_ip.delete()
1151
1211
        return ngi, new_ip
1152
1212
 
1257
1317
                if ngi is not None and ngi.subnet is not None:
1258
1318
                    discovered_subnets.append(ngi.subnet)
1259
1319
 
 
1320
        if len(discovered_subnets) == 0:
 
1321
            node = self.node
 
1322
            if parent is not None:
 
1323
                node = parent
 
1324
            if node is None:
 
1325
                hostname = "<unknown>"
 
1326
            else:
 
1327
                hostname = "'%s'" % node.hostname
 
1328
            log_string = (
 
1329
                "%s: Attempted to claim a static IP address, but no "
 
1330
                "associated subnet could be found. (Recommission node %s "
 
1331
                "in order for MAAS to discover the subnet.)" %
 
1332
                (self.get_log_string(), hostname)
 
1333
            )
 
1334
            maaslog.warning(log_string)
 
1335
            raise StaticIPAddressExhaustion(log_string)
 
1336
 
1260
1337
        if requested_address is None:
1261
1338
            # No requested address so claim a STATIC IP on all DISCOVERED
1262
1339
            # subnets for this interface.
1271
1348
            # No valid subnets could be used to claim a STATIC IP address.
1272
1349
            if not any(static_ips):
1273
1350
                maaslog.error(
1274
 
                    "Tried to allocate an IP to interface <%s>, but its "
1275
 
                    "cluster interface is not known.", unicode(self))
 
1351
                    "Attempted sticky IP allocation failed for %s: could not "
 
1352
                    "find a cluster interface.", self.get_log_string())
1276
1353
                return []
1277
1354
            else:
1278
1355
                return static_ips
1294
1371
            else:
1295
1372
                raise StaticIPAddressOutOfRange(
1296
1373
                    "requested_address '%s' is not in a managed subnet for "
1297
 
                    "this interface '%s'" % (requested_address, self.name))
 
1374
                    "interface '%s'." % (
 
1375
                        requested_address, self.get_name()))
1298
1376
 
1299
1377
    def _get_parent_node(self):
1300
1378
        """Return the parent node for this interface, if it exists (and this