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)))
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()
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
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)))
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
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), {