Example #1
0
 def sync_prefixes(self, prefixes):
     """
     Apply prefixes to database
     :param prefixes:
     :return:
     """
     # vpn_id -> [prefix, ]
     vrf_prefixes = defaultdict(list)
     for vpn_id, p in prefixes:
         vrf_prefixes[vpn_id] += [p]
     # build vpn_id -> VRF mapping
     self.logger.debug("Building VRF map")
     vrfs = {}
     for vpn_id in vrf_prefixes:
         vrf = VRF.get_by_vpn_id(vpn_id)
         if vrf:
             vrfs[vpn_id] = vrf
     missed_vpn_id = set(vrf_prefixes) - set(vrfs)
     if missed_vpn_id:
         self.logger.info("RD missed in VRF database and to be ignored: %s", ", ".join(missed_vpn_id))
     #
     self.logger.debug("Getting prefixes to synchronize")
     for vpn_id in vrfs:
         vrf = vrfs[vpn_id]
         seen = set()
         for p in Prefix.objects.filter(vrf=vrf, prefix__in=vrf_prefixes[vpn_id]):
             norm_prefix = IP.expand(p.prefix)
             # Confirmed prefix, apply changes and touch
             prefix = prefixes[vpn_id, norm_prefix]
             self.apply_prefix_changes(p, prefix)
             seen.add(norm_prefix)
         for p in set(vrf_prefixes[vpn_id]) - seen:
             # New prefix, create
             self.create_prefix(prefixes[vpn_id, p])
Example #2
0
 def create_address(self, address):
     """
     Create new address
     :param address: DiscoveredAddress instance
     :return:
     """
     if self.is_ignored_address(address):
         return
     vrf = VRF.get_by_vpn_id(address.vpn_id)
     self.ensure_afi(vrf, address)
     if not self.has_address_permission(vrf, address):
         self.logger.debug(
             "Do not creating vpn_id=%s address=%s: Disabled by policy",
             address.vpn_id, address.address)
         metrics["address_creation_denied"] += 1
         return
     a = Address(vrf=vrf,
                 address=address.address,
                 name=self.get_address_name(address),
                 fqdn=address.fqdn,
                 profile=address.profile,
                 description=address.description,
                 source=address.source,
                 mac=address.mac)
     if address.source in LOCAL_SRC:
         a.managed_object = self.object
         a.subinterface = address.subinterface
     self.logger.info(
         "Creating address %s (%s): name=%s fqdn=%s mac=%s profile=%s source=%s",
         a.address, a.vrf.name, a.name, a.fqdn, a.mac, a.profile.name,
         a.source)
     a.save()
     self.fire_seen(a)
     metrics["address_created"] += 1
Example #3
0
 def sync_ipam(self):
     """
     Synchronize FQDN and address with IPAM
     """
     from noc.ip.models.address import Address
     from noc.ip.models.vrf import VRF
     # Generate FQDN from template
     fqdn = self.object_profile.get_fqdn(self)
     # Get existing IPAM record
     vrf = self.vrf if self.vrf else VRF.get_global()
     try:
         a = Address.objects.get(vrf=vrf, address=self.address)
     except Address.DoesNotExist:
         # Create new address
         Address(
             vrf=vrf,
             address=self.address,
             fqdn=fqdn,
             managed_object=self
         ).save()
         return
     # Update existing address
     if (a.managed_object != self or
         a.address != self.address or a.fqdn != fqdn):
         a.managed_object = self
         a.address = self.address
         a.fqdn = fqdn
         a.save()
Example #4
0
 def create_vpn(self, vpn):
     """
     Create new vpn
     :param vpn: DiscoveredVPN instance
     :return:
     """
     if not self.has_vpn_permission(vpn):
         self.logger.debug(
             "Do not creating rd=%s vpn_id=%s name=%s Disabled by policy",
             vpn.rd, vpn.vpn_id, vpn.name)
         metrics["vpn_creation_denied"] += 1
         return
     name = self.get_vpn_name(vpn)
     # Check for naming clash
     if VRF.objects.filter(name=name).exists():
         # Naming clash
         old_name = name
         name = self.get_unique_vpn_name(vpn)
         self.logger.info(
             "Name '%s' is already exists with other vpn_id. Rename to '%s'",
             old_name, name)
         metrics["vpn_name_clash"] += 1
     #
     p = VRF(name=name,
             rd=vpn.rd,
             vpn_id=vpn.vpn_id,
             profile=vpn.profile,
             source=vpn.source)
     self.logger.info("Creating vpn %s: name=%s rd=%s profile=%s source=%s",
                      p.vpn_id, p.name, p.rd, p.profile.name, p.source)
     p.save()
     p.fire_event("seen")
     metrics["vpn_created"] += 1
Example #5
0
 def api_bulk_import(self, request, items):
     n = 0
     for i in items:
         if not VRF.objects.filter(name=i["name"], rd=i["rd"]).exists():
             # Add only new
             VRF(name=i["name"],
                 vrf_group=i["vrf_group"],
                 rd=i["rd"],
                 afi_ipv4=i["afi_ipv4"],
                 afi_ipv6=i["afi_ipv6"],
                 description=i.get("description")).save()
             n += 1
     return {"status": True, "imported": n}
Example #6
0
    def unregister_dynamic_usage(self,
                                 vrf=None,
                                 name="default",
                                 technology="IPoE"):
        """
        Decrease dynamic pool usage
        """
        ## Avoid circular references
        from noc.ip.models.vrf import VRF
        from noc.ip.models.dynamicippoolusage import DynamicIPPoolUsage

        self._check_technology(technology)
        if not vrf:
            vrf = VRF.get_global()
        DynamicIPPoolUsage.unregister_usage(self, vrf, name, technology)
Example #7
0
 def get_data(self, **kwargs):
     vrf_id = VRF.get_global().id
     return self.from_query(title=self.title,
                            columns=[_("Prefix")],
                            query="""
         SELECT prefix
         FROM   ip_prefix p
         WHERE
             vrf_id=%s
             AND afi='4'
             AND masklen(prefix)=30
             AND NOT EXISTS (SELECT * FROM ip_address WHERE vrf_id=%s AND afi='4' AND prefix=p.prefix)
         ORDER BY prefix
         """,
                            params=[vrf_id, vrf_id],
                            enumerate=True)
Example #8
0
 def sync_addresses(self, addresses):
     """
     Apply addresses to database
     :param addresses:
     :return:
     """
     # vpn_id -> [address, ]
     vrf_addresses = defaultdict(list)
     for vpn_id, a in addresses:
         vrf_addresses[vpn_id] += [a]
     # build vpn_id -> VRF mapping
     self.logger.debug("Building VRF map")
     vrfs = {}
     for vpn_id in vrf_addresses:
         vrf = VRF.get_by_vpn_id(vpn_id)
         if vrf:
             vrfs[vpn_id] = vrf
     missed_vpn_id = set(vrf_addresses) - set(vrfs)
     if missed_vpn_id:
         self.logger.info(
             "VPN ID are missed in VRF database and to be ignored: %s",
             ", ".join(missed_vpn_id))
     #
     self.logger.debug("Getting addresses to synchronize")
     for vpn_id in vrfs:
         vrf = vrfs[vpn_id]
         seen = set()
         for a in Address.objects.filter(vrf=vrf,
                                         address__in=vrf_addresses[vpn_id]):
             norm_address = IP.expand(a.address)
             # Confirmed address, apply changes and touch
             address = addresses[vpn_id, norm_address]
             self.apply_address_changes(a, address)
             seen.add(norm_address)
         for a in set(vrf_addresses[vpn_id]) - seen:
             # New address, create
             self.create_address(addresses[vpn_id, a])
     # Detaching hanging addresses
     self.logger.debug("Checking for hanging addresses")
     for a in Address.objects.filter(managed_object=self.object):
         norm_address = IP.expand(a.address)
         address = addresses.get((a.vrf.vpn_id, norm_address))
         if not address or address.source not in LOCAL_SRC:
             self.logger.info("Detaching %s:%s", a.vrf.name, a.address)
             a.managed_object = None
             a.save()
Example #9
0
    def get_or_create(self, object, name, rd):
        """
        :param object:
        :param name:
        :param rd:
        :return:
        """
        def set_cache(vrf):
            self.cache_vrf_by_rd[vrf.rd] = vrf
            self.cache_vrf_by_name[vrf.name] = vrf
            return vrf

        if name == "default":
            if object.vrf:
                # Use object's VRF is set
                return object.vrf
            # Get default VRF
            try:
                return self.cache_vrf_by_name["default"]
            except KeyError:
                return set_cache(VRF.get_global())
        # Non-default VRF
        if not rd:
            rd = VRF.generate_rd(name)
        # Lookup RD cache
        try:
            return self.cache_vrf_by_rd[rd]
        except KeyError:
            pass
        # Lookup database
        try:
            return set_cache(VRF.objects.get(rd=rd))
        except VRF.DoesNotExist:
            pass
        # VRF Not found, create
        # Generate unique VRF in case of names clash
        vrf_name = name
        if VRF.objects.filter(name=vrf_name).exists():
            # Name clash, generate new name by appending RD
            vrf_name += "_%s" % rd
            self.info(
                object,
                "Conflicting names for VRF %s. Using fallback name %s" %
                (name, vrf_name))
        # Create VRF
        vrf = VRF(name=vrf_name, rd=rd, vrf_group=VRF.get_global().vrf_group)
        vrf.save()
        return set_cache(vrf)
Example #10
0
    def get_data(self, request, **kwargs):
        vrf_id = VRF.get_global().id
        return self.from_query(title=self.title,
                               columns=["FQDN", "AFI", "N", "Addresses"],
                               query="""
SELECT fqdn, afi, COUNT(*),
    array_to_string(ARRAY(SELECT address
                         FROM ip_address
                         WHERE fqdn=a.fqdn
                            AND vrf_id=%s
                            AND afi=a.afi
                        ORDER BY address),', ')
FROM ip_address a
WHERE vrf_id=%s
GROUP BY 1, 2
HAVING COUNT(*)>1
ORDER BY 3 DESC""",
                               params=[vrf_id, vrf_id])
Example #11
0
 def get_usage(cls,
               termination_group,
               vrf=None,
               pool_name="default",
               technology="IPoE"):
     if not vrf:
         vrf = VRF.get_global()
     r = cls._get_collection().find_one(
         {
             "termination_group": termination_group.id,
             "vrf": vrf.id,
             "pool_name": pool_name,
             "technology": technology
         }, {"usage": 1})
     if r:
         return r["usage"]
     else:
         return 0
Example #12
0
 def unregister_usage(cls,
                      termination_group,
                      vrf=None,
                      pool_name="default",
                      technology="IPoE"):
     """
     Decrease usage counter
     """
     if not vrf:
         vrf = VRF.get_global()
     cls._get_collection().update(
         {
             "termination_group": termination_group.id,
             "vrf": vrf.id,
             "pool_name": pool_name,
             "technology": technology
         }, {"$inc": {
             "usage": -1
         }},
         upsert=True)
Example #13
0
 def create_prefix(self, prefix):
     """
     Create new prefix
     :param prefix: DiscoveredPrefix instance
     :return:
     """
     if self.is_ignored_prefix(prefix):
         return
     vrf = VRF.get_by_vpn_id(prefix.vpn_id)
     self.ensure_afi(vrf, prefix)
     if not self.has_prefix_permission(vrf, prefix):
         self.logger.debug(
             "Do not creating vpn_id=%s asn=%s prefix=%s: Disabled by policy",
             prefix.vpn_id,
             prefix.asn.asn if prefix.asn else None,
             prefix.prefix,
         )
         metrics["prefix_creation_denied"] += 1
         return
     p = Prefix(
         vrf=vrf,
         prefix=prefix.prefix,
         name=self.get_prefix_name(prefix),
         profile=prefix.profile,
         asn=prefix.asn,
         description=prefix.description,
         source=prefix.source,
     )
     self.logger.info(
         "Creating prefix %s (%s): name=%s profile=%s source=%s",
         p.prefix,
         p.vrf.name,
         p.name,
         p.profile.name,
         p.source,
     )
     p.save()
     self.fire_seen(p)
     metrics["prefix_created"] += 1
Example #14
0
    def get_data(self, **kwargs):
        def reverse_format(p):
            n, m = p.split("/")
            n = n.split(".")[:-1]
            n.reverse()
            return "%s.%s.%s.in-addr.arpa" % (n[0], n[1], n[2])

        vrf_id = VRF.get_global().id
        return self.from_query(
            title=self.title,
            columns=["Prefix",
                     TableColumn("Zone", format=reverse_format)],
            query="""
                SELECT prefix,prefix
                FROM ip_prefix
                WHERE vrf_id=%s
                    AND masklen(prefix)=24
                    AND regexp_replace(host(prefix),E'([0-9]+)\\\\.([0-9]+)\\\\.([0-9]+)\\\\.([0-9]+)',E'\\\\3.\\\\2.\\\\1.in-addr.arpa')
                        NOT IN (SELECT name FROM dns_dnszone WHERE name LIKE '%%.in-addr.arpa')
                ORDER BY 1
            """,
            params=[vrf_id],
            enumerate=True)
Example #15
0
    def import_zone(
        self,
        path=None,
        axfr=False,
        zone_profile=None,
        address_profile=None,
        transfer_zone=None,
        nameserver=None,
        source_address=None,
        dry_run=False,
        force=False,
        clean=False,
    ):
        self.print("Loading zone file '%s'" % path)
        self.print("Parsing zone file using BIND parser")
        if path:
            with open(path) as f:
                rrs = self.iter_bind_zone_rr(f)
                try:
                    soa = next(rrs)
                except StopIteration:
                    raise CommandError("Unable to parse zone file from %s" %
                                       path)
                zone = self.from_idna(soa.zone)
                z = self.dns_zone(zone, zone_profile, dry_run, clean)
                # Populate zone
                vrf = VRF.get_global()
                zz = zone + "."
                lz = len(zz)
                if z.is_forward:
                    zp = None
                elif z.is_reverse_ipv4:
                    # Calculate prefix for reverse zone
                    zp = ".".join(reversed(zone[:-13].split("."))) + "."
                elif z.is_reverse_ipv6:
                    raise CommandError(
                        "IPv6 reverse import is not implemented")
                else:
                    raise CommandError("Unknown zone type")
                for rr in rrs:
                    name = rr.name
                    if name.endswith(zz):
                        name = name[:-lz]
                    if name.endswith("."):
                        name = name[:-1]
                    # rr = None
                    # Skip zone NS
                    if rr.type == "NS" and not name:
                        continue
                    if rr.type in ("A", "AAAA"):
                        self.create_address(
                            zone,
                            vrf,
                            rr.rdata,
                            "%s.%s" % (name, zone) if name else zone,
                            address_profile,
                            dry_run=dry_run,
                            force=force,
                        )
                    elif rr.type == "PTR":
                        if "." in name:
                            address = zp + ".".join(reversed(name.split(".")))
                        else:
                            address = zp + name
                        self.create_address(
                            zone,
                            vrf,
                            address,
                            rr.rdata,
                            address_profile,
                            dry_run=dry_run,
                            force=force,
                        )
                    else:
                        zrr = DNSZoneRecord(
                            zone=z,
                            name=name,
                            type=rr.type,
                            ttl=rr.ttl,
                            priority=rr.priority,
                            content=rr.rdata,
                        )
                        self.print("Creating %s %s" % (rr.type, rr.name))
                        if not dry_run:
                            zrr.save()
        if axfr:
            data = self.load_axfr(nameserver, transfer_zone, source_address)
            zone = self.from_idna(transfer_zone)
            z = self.dns_zone(zone, zone_profile, dry_run, clean)
            # Populate zone
            vrf = VRF.get_global()
            zz = zone + "."
            lz = len(zz)
            if z.is_forward:
                zp = None
            elif z.is_reverse_ipv4:
                # Calculate prefix for reverse zone
                zp = ".".join(reversed(zone[:-13].split("."))) + "."
            elif z.is_reverse_ipv6:
                raise CommandError("IPv6 reverse import is not implemented")
            else:
                raise CommandError("Unknown zone type")
            for row in data:
                row = row.strip()
                if row == "" or row.startswith(";"):
                    continue
                row = row.split()

                if len(row) != 5 or row[2] != "IN" or row[3] not in ("A",
                                                                     "AAAA",
                                                                     "PTR"):
                    continue
                if row[3] in ("A", "AAAA"):
                    name = row[0]
                    if name.endswith(zz):
                        name = name[:-lz]
                    if name.endswith("."):
                        name = name[:-1]
                    self.create_address(
                        zone,
                        vrf,
                        row[4],
                        "%s.%s" % (name, zone) if name else zone,
                        address_profile,
                        dry_run=dry_run,
                        force=force,
                    )
                if row[3] == "PTR":
                    name = row[4]
                    if name.endswith(zz):
                        name = name[:-lz]
                    if name.endswith("."):
                        name = name[:-1]
                    # @todo: IPv6
                    if "." in row[0]:
                        address = ".".join(reversed(row[0].split(".")[:-3]))
                    else:
                        address = zp + name
                    fqdn = row[4]
                    if fqdn.endswith("."):
                        fqdn = fqdn[:-1]
                    self.create_address(zone,
                                        vrf,
                                        address,
                                        fqdn,
                                        address_profile,
                                        dry_run=dry_run,
                                        force=force)
Example #16
0
 def import_zone(self,
                 path,
                 zone_profile,
                 address_profile,
                 dry_run=False,
                 force=False,
                 clean=False):
     self.print("Loading zone file '%s'" % path)
     self.print("Parsing zone file using BIND parser")
     with open(path) as f:
         rrs = self.iter_bind_zone_rr(f)
         try:
             soa = next(rrs)
         except StopIteration:
             raise CommandError("Unable to parse zone file from %s" % path)
         zone = self.from_idna(soa.zone)
         z = DNSZone.get_by_name(zone)
         if z:
             self.print("Using existing zone '%s'" % zone)
         else:
             self.print("Creating zone '%s'" % zone)
             z = DNSZone(name=zone, profile=zone_profile)
             clean = False  # Nothing to clean
         if z.profile.id != zone_profile.id:
             self.print("Setting profile to '%s'" % zone_profile.name)
             z.profile = zone_profile
         # Apply changes
         if dry_run:
             z.clean()  # Set type
         else:
             z.save()
         #  Clean zone when necessary
         if clean:
             self.print("Cleaning zone")
             for rr in DNSZoneRecord.objects.filter(zone=z):
                 self.print("Removing %s %s" % (rr.type, rr.name))
                 if not dry_run:
                     rr.delete()
         # Populate zone
         vrf = VRF.get_global()
         zz = zone + "."
         lz = len(zz)
         if z.is_forward:
             zp = None
         elif z.is_reverse_ipv4:
             # Calculate prefix for reverse zone
             zp = ".".join(reversed(zone[:-13].split("."))) + "."
         elif z.is_reverse_ipv6:
             raise CommandError("IPv6 reverse import is not implemented")
         else:
             raise CommandError("Unknown zone type")
         for rr in rrs:
             name = rr.name
             if name.endswith(zz):
                 name = name[:-lz]
             if name.endswith("."):
                 name = name[:-1]
             # rr = None
             # Skip zone NS
             if rr.type == "NS" and not name:
                 continue
             if rr.type in ("A", "AAAA"):
                 self.create_address(
                     zone,
                     vrf,
                     rr.rdata,
                     "%s.%s" % (name, zone) if name else zone,
                     address_profile,
                     dry_run=dry_run,
                     force=force,
                 )
             elif rr.type == "PTR":
                 if "." in name:
                     address = zp + ".".join(reversed(name.split(".")))
                 else:
                     address = zp + name
                 self.create_address(zone,
                                     vrf,
                                     address,
                                     rr.rdata,
                                     address_profile,
                                     dry_run=dry_run,
                                     force=force)
             else:
                 zrr = DNSZoneRecord(
                     zone=z,
                     name=name,
                     type=rr.type,
                     ttl=rr.ttl,
                     priority=rr.priority,
                     content=rr.rdata,
                 )
                 self.print("Creating %s %s" % (rr.type, rr.name))
                 if not dry_run:
                     zrr.save()
Example #17
0
 def import_zone(self, path, options):
     is_test = bool(options["test"])
     self.info("Loading zone file '%s'" % path)
     with open(path) as f:
         data = f.read()
     self.info("Parsing zone file using BIND parser")
     zone, rrs = self.parse_bind_zone(data)
     if not zone or not rrs:
         raise CommandError("Unable to parse zone file")
     # Find profile
     profile = self.get_profile(options)
     # Get or create zone
     to_clean = bool(options["clean"])
     try:
         z = DNSZone.objects.get(name=zone)
         self.info("Using existing zone '%s'" % z)
     except DNSZone.DoesNotExist:
         self.info("Creating zone '%s'" % zone)
         z = DNSZone(name=zone, profile=profile)
         to_clean = False  # Nothing to clean yet
     if z.profile != profile:
         self.info("Setting profile to '%s'" % profile)
         z.profile = profile
     if not is_test:
         z.save()
     # Clean zone when necessary
     if to_clean and z.id:
         self.info("Cleaning zone")
         for rr in z.dnszonerecord_set.all():
             self.info("Removing %s %s" % (rr.type, rr.name))
             if not is_test:
                 rr.delete()
     # Populate zone
     vrf = VRF.get_global()
     zz = zone + "."
     lz = len(zz)
     if zone.endswith(".in-addr.arpa"):
         # Calculate prefix for reverse zone
         zp = zone[:-13].split(".")
         zp.reverse()
         zp = ".".join(zp) + "."
     else:
         # @todo: IPv6 reverse
         zp = None
     for name, t, value, ttl, priority in rrs:
         # print name, t, value
         if name.endswith(zz):
             name = name[:-lz]
         if name.endswith("."):
             name = name[:-1]
         rr = None
         if (t == "SOA") or (t == "NS" and not name):
             continue
         if t in ("A", "AAAA"):
             afi = "4" if t == "A" else "6"
             self.create_address(
                 zone, vrf, afi, value,
                 "%s.%s" % (name, zone) if name else zone, is_test)
         elif t == "PTR":
             if not zp:
                 raise CommandError("IPv6 reverse zone import is still not supported")
             address = zp + name
             afi = "6" if ":" in address else "4"
             self.create_address(zone, vrf, afi, address, value, is_test)
         else:
             rr = DNSZoneRecord(
                 zone=z, name=name, type=t,
                 ttl=ttl, priority=priority,
                 content=value
             )
         if rr:
             self.info("Creating %s %s" % (rr.type, rr.name))
             if not is_test:
                 rr.save()