Beispiel #1
0
    def check_reserved_addresses_in_use(self):
        """TODO: DOC

        """
        # Need to import Utils here, since Utils imports this module,
        # and we cannot have circular module dependencies.
        from Cerebrum.modules.dns.Utils import Find
        default_zone = self.const.DnsZone(getattr(cereconf, 'DNS_DEFAULT_ZONE', 'uio'))
        find = Find(self._db, default_zone)

        ip_number = IPNumber.IPNumber(self._db)
        ip_number.clear()

        res_adr_in_use = []

        for row in ip_number.find_in_range(self.ip_min, self.ip_max):
            current_address = long(row['ipnr'])
            if current_address in self.reserved_adr:
                res_adr_in_use.append(IPCalc.long_to_ip(current_address))

        if res_adr_in_use:
            res_adr_in_use.sort()
            raise SubnetError(
                "The following reserved ip's are already in use " +
                "on (new?) subnet %s/%s: " % (self.subnet_ip, self.subnet_mask) +
                "'%s'." % (', '.join(res_adr_in_use)))
Beispiel #2
0
    def populate(self, subnet, description, vlan=None):
        """Populate subnet instance's attributes.

        @type subnet: string
        @param subnet: A string that represents the subnet. Example:
            10.0.0.0/16. The last '.0' is not required, e.g. 10.0.0/16.

        @type description: string
        @param description: Something that describes the given subnet. It is
            free text, but local policies might use this in a parsable format
            to describe the usage of the given subnet.

        @type vlan: int
        @param vlan: A number that represents what VLAN the subnet corresponds
            to.

        """
        Entity.populate(self, self.const.entity_dns_subnet)
        # If __in_db is present, it must be True; calling populate on
        # an object where __in_db is present and False is very likely
        # a programming error.
        #
        # If __in_db in not present, we'll set it to False.
        try:
            if not self.__in_db:
                raise RuntimeError("populate() called multiple times.")
        except AttributeError:
            self.__in_db = False

        self.subnet_ip, subnet_mask = subnet.split('/')
        self.subnet_mask = int(subnet_mask)
        if len(self.subnet_ip.split('.')) == 3:
            self.subnet_ip = self.subnet_ip + ".0"

        (self.ip_min,
         self.ip_max) = IPCalc().ip_range_by_netmask(self.subnet_ip,
                                                     self.subnet_mask)
        self.description = description
        self.vlan = vlan
        self.name_prefix = ''

        max_res = max(cereconf.DEFAULT_RESERVED_BY_NET_SIZE.values())
        self.no_of_reserved_adr = cereconf.DEFAULT_RESERVED_BY_NET_SIZE.get(
            self.subnet_mask, max_res)
        self.calculate_reserved_addresses()
Beispiel #3
0
    def get_relevant_ips(self, subnet_or_ip, force=False, no_of_addrs=None):
        """
        Returns a list of available IPs. If a subnet is given as input,
        the list consists of avaiable IPs on the subnet. If a specific IP is
        given as input, the list will only contain that IP.

        :param subnet_or_ip: An IPv4/IPv6 subnet or IP-address
        :type  subnet_or_ip: str
        :param force: Indicates if the method should attempt to force the
                      operation, even if there is no record that the IP given
                      as input belongs to any subnet records.
        :type  force: boolean
        :param no_of_addrs: The max number of ips to be returned.
        :type  no_of_addrs: int

        :returns: A list of available IPs found, or a list containing only
                  the specified IP given to the method in subnet_or_ip, if
                  it is evaluated to a full IP.
        :rtype:   list
        """
        subnet, ip = self._parser.parse_subnet_or_ip(subnet_or_ip)
        if subnet is None and not force:
            raise CerebrumError("Unknown subnet. Must force")

        elif subnet is None and ip is None:
            raise CerebrumError("Please specify a valid subnet or IP-address.")

        elif subnet is not None and ip is None:

            first = subnet_or_ip.split('/')[0]

            if IPUtils.is_valid_ipv4(first):
                first = IPCalc.ip_to_long(first)

            elif IPv6Utils.is_valid_ipv6(first):
                first = None

            free_ip_numbers = self._find.find_free_ip(subnet,
                                                      first=first,
                                                      no_of_addrs=no_of_addrs)
        else:
            free_ip_numbers = [ip]

        return free_ip_numbers
Beispiel #4
0
    def get_relevant_ips(self, subnet_or_ip, force=False, no_of_addrs=None):
        """
        Returns a list of available IPs. If a subnet is given as input,
        the list consists of avaiable IPs on the subnet. If a specific IP is
        given as input, the list will only contain that IP.

        :param subnet_or_ip: An IPv4/IPv6 subnet or IP-address
        :type  subnet_or_ip: str
        :param force: Indicates if the method should attempt to force the
                      operation, even if there is no record that the IP given
                      as input belongs to any subnet records.
        :type  force: boolean
        :param no_of_addrs: The max number of ips to be returned.
        :type  no_of_addrs: int

        :returns: A list of available IPs found, or a list containing only
                  the specified IP given to the method in subnet_or_ip, if
                  it is evaluated to a full IP.
        :rtype:   list
        """
        subnet, ip = self._parser.parse_subnet_or_ip(subnet_or_ip)
        if subnet is None and not force:
            raise CerebrumError("Unknown subnet. Must force")

        elif subnet is None and ip is None:
            raise CerebrumError("Please specify a valid subnet or IP-address.")

        elif subnet is not None and ip is None:

            first = subnet_or_ip.split('/')[0]

            if IPUtils.is_valid_ipv4(first):
                first = IPCalc.ip_to_long(first)

            elif IPv6Utils.is_valid_ipv6(first):
                first = None

            free_ip_numbers = self._find.find_free_ip(subnet, first=first,
                                                      no_of_addrs=no_of_addrs)
        else:
            free_ip_numbers = [ip]

        return free_ip_numbers
Beispiel #5
0
    def check_reserved_addresses_in_use(self):
        """TODO: DOC

        """
        ip_number = IPNumber.IPNumber(self._db)
        ip_number.clear()

        res_adr_in_use = []

        for row in ip_number.find_in_range(self.ip_min, self.ip_max):
            current_address = long(row['ipnr'])
            if current_address in self.reserved_adr:
                res_adr_in_use.append(IPCalc.long_to_ip(current_address))

        if res_adr_in_use:
            res_adr_in_use.sort()
            raise SubnetError(
                "The following reserved ip's are already in use"
                " on (new?) subnet %s/%s: '%s'." %
                (self.subnet_ip, self.subnet_mask, ', '.join(res_adr_in_use)))
Beispiel #6
0
    def subnet_info(self, operator, identifier):
        """Lists the following information about the given subnet:

        * Subnett
        * Netmask
        * Entity ID
        * Description
        * Name-prefix
        * VLAN number
        * DNS-delegation status
        * Range of IPs on subnet
        * Number of reserved addresses
        * A list of the reserved adresses
        """
        s = Subnet(self.db)
        s.find(identifier)

        if s.dns_delegated:
            delegated = "Yes"
        else:
            delegated = "No"

        data = {
            'subnet': "%s/%s" % (s.subnet_ip, s.subnet_mask),
            'entity_id': str(s.entity_id),
            'netmask': IPCalc.netmask_to_ip(s.subnet_mask),
            'desc': s.description,
            'delegated': delegated,
            'name_prefix': s.name_prefix,
            'no_of_res_adr': str(s.no_of_reserved_adr)
        }

        if s.vlan_number is not None:
            data['vlan'] = str(s.vlan_number)
        else:
            data['vlan'] = "(None)"

        data['ip_range'] = "%s - %s" % (IPCalc.long_to_ip(s.ip_min),
                                        IPCalc.long_to_ip(s.ip_max))

        # Calculate number of used and unused IP-addresses on this subnet
        #                              ^^^^^^ excluding reserved addresses
        data['used'] = str(len(self._find.find_used_ips(s.subnet_ip)))
        try:
            data['unused'] = str(len(self._find.find_free_ip(s.subnet_ip)))
        except CerebrumError:
            data['unused'] = "0"

        reserved_adresses = list(s.reserved_adr)

        if reserved_adresses:
            reserved_adresses.sort()
            data["res_adr1"] = "%s (net)" % IPCalc.long_to_ip(reserved_adresses.pop(0))
        else:
            data["res_adr1"] = "(None)"

        ret = [data, ]

        if reserved_adresses:
            last_ip = reserved_adresses.pop()
            for address in reserved_adresses:
                ret.append({'res_adr': IPCalc.long_to_ip(address)})
            ret.append({'res_adr': "%s (broadcast)" % IPCalc.long_to_ip(last_ip)})

        return ret
Beispiel #7
0
    def find(self, identifier):
        """Find and instantiate the subnet entity with data from the db.

        @type identifier: mixed
        @param identifier:
            The identifier of the Subnet. Note that the DNS module behaves a bit
            differently than other Cerebrum modules, in that this find method
            accepts other input than entity_id. Possibilities are:

                - A string containing the entity_id, prefixed with 'entity_id:'
                  or 'id:'.

                - A string with a subnet address, e.g. '10.0.1.0/16'.

                - A string with an IP address, e.g. '10.0.1.57'.

        """
        binds = {}

        if identifier is None:
            raise SubnetError("Unable to find IPv4 subnet identified by '%s'" % identifier)

        if isinstance(identifier, (str, unicode)) and identifier.count(':') >= 2:
            # This is probably an IPv6 subnet
            raise SubnetError("Unable to find IPv4 subnet identified by '%s'" % identifier)

        if isinstance(identifier, (int, long)):
            # The proper way of running find()
            where_param = "entity_id = :e_id"
            binds['e_id'] = identifier
        elif identifier.startswith('id:') or identifier.startswith('entity_id:'):
            # E.g. 'id:X' or 'entity_id:X';
            where_param = "entity_id = :e_id"
            try:
                binds['e_id'] = int(identifier.split(':')[1])
            except ValueError:
                raise SubnetError("Entity ID must be an integer")
        elif identifier.find('/') > 0:
            # A '/' indicates a subnet spec: just need the ip
            where_param = "subnet_ip = :subnet_ip"
            subnet_ip = identifier.split('/')[0]
            if len(subnet_ip.split(".")) == 3:
                subnet_ip += ".0"
            binds['subnet_ip'] = subnet_ip
        else:
            # Last valid type is simply an IP; need to find correct range
            if len(identifier.split(".")) == 3:
                identifier += ".0"
            where_param = "ip_min <= :ip AND ip_max >= :ip"
            binds['ip'] = IPCalc.ip_to_long(identifier)

        try:
            (eid, self.subnet_ip, self.ip_min, self.ip_max,
             self.description, self.dns_delegated, self.name_prefix,
             self.vlan_number, self.no_of_reserved_adr) = self.query_1(
                 """SELECT entity_id, subnet_ip, ip_min, ip_max, description,
                           dns_delegated, name_prefix, vlan_number,
                           no_of_reserved_adr
                    FROM [:table schema=cerebrum name=dns_subnet]
                    WHERE %s""" % where_param, binds)

            self.__super.find(eid)

            self.subnet_mask = Subnet.calculate_subnet_mask(self.ip_min, self.ip_max)
            self.calculate_reserved_addresses()

        except NotFoundError:
            raise SubnetError("Unable to find IPv4 subnet identified by '%s'" % identifier)

        self.__in_db = True
        self.__updated = []
"""Usage: generate_subnet_ldif.py [--logger-name=console ...]

Write IP subnet information from Cerebrum
to an LDIF file, which can then be loaded into LDAP.
See Cerebrum/default_config.py:LDAP_SUBNETS for configuration.
"""

import cerebrum_path
import cereconf
from Cerebrum.Utils import Factory
from Cerebrum.modules.LDIFutils import ldapconf, iso2utf, \
     ldif_outfile, end_ldif_outfile, entry_string, container_entry_string
from Cerebrum.modules.dns.Subnet import Subnet
from Cerebrum.modules.dns.IPUtils import IPCalc

netmask_to_ip = IPCalc().netmask_to_ip


def write_subnet_ldif():
    DN = ldapconf('SUBNETS', 'dn')
    startAttr, endAttr, objectClasses = ldapconf('SUBNETS', 'rangeSchema')
    objectClasses = ('top', 'ipNetwork') + tuple(objectClasses)
    db = Factory.get('Database')()
    f = ldif_outfile('SUBNETS')
    f.write(container_entry_string('SUBNETS'))
    for row in Subnet(db).search():
        cn = "%s/%s" % (row['subnet_ip'], row['subnet_mask'])
        desc = row['description']
        f.write(
            entry_string(
                "cn=%s,%s" % (cn, DN), {