コード例 #1
0
ファイル: add_dns_environment.py プロジェクト: jrha/aquilon
    def render(self, session, dns_environment, comments, **arguments):
        validate_basic("DNS environment", dns_environment)
        DnsEnvironment.get_unique(session, dns_environment, preclude=True)

        db_dnsenv = DnsEnvironment(name=dns_environment, comments=comments)
        session.add(db_dnsenv)
        session.flush()
        return
コード例 #2
0
ファイル: host.py プロジェクト: piojo/aquilon
def hostlist_to_hosts(session, hostlist):
    dbdns_env = DnsEnvironment.get_unique_or_default(session)
    failed = []
    dbhosts = []
    dns_domains = {}
    for host in hostlist:
        if "." not in host:
            failed.append("%s: Not an FQDN." % host)
            continue
        short, dns_domain = host.split(".", 1)
        try:
            if dns_domain not in dns_domains:
                dbdns_domain = DnsDomain.get_unique(session, dns_domain,
                                                    compel=True)

                dns_domains[dns_domain] = dbdns_domain

            dbdns_rec = DnsRecord.get_unique(session, name=short,
                                             dns_domain=dns_domains[dns_domain],
                                             dns_environment=dbdns_env,
                                             query_options=[joinedload('hardware_entity')],
                                             compel=True)
            if not dbdns_rec.hardware_entity or \
               not dbdns_rec.hardware_entity.host:
                raise NotFoundException("Host %s not found." % host)
            dbhosts.append(dbdns_rec.hardware_entity.host)

        except NotFoundException, err:
            failed.append("%s: %s" % (host, err))
            continue
        except ArgumentError, err:
            failed.append("%s: %s" % (host, err))
            continue
コード例 #3
0
ファイル: update_alias.py プロジェクト: ned21/aquilon
    def render(self, session, logger, fqdn, dns_environment, target, comments,
               **kwargs):
        dbdns_env = DnsEnvironment.get_unique_or_default(
            session, dns_environment)
        dbalias = Alias.get_unique(session,
                                   fqdn=fqdn,
                                   dns_environment=dbdns_env,
                                   compel=True)

        old_target_fqdn = str(dbalias.target.fqdn)
        old_comments = dbalias.comments

        if target:
            old_target = dbalias.target
            dbalias.target = create_target_if_needed(session, logger, target,
                                                     dbdns_env)
            if dbalias.target != old_target:
                delete_target_if_needed(session, old_target)

        if comments is not None:
            dbalias.comments = comments

        session.flush()

        if dbdns_env.is_default and dbalias.fqdn.dns_domain.name == "ms.com":
            dsdb_runner = DSDBRunner(logger=logger)
            dsdb_runner.update_alias(fqdn, dbalias.target.fqdn,
                                     dbalias.comments, old_target_fqdn,
                                     old_comments)
            dsdb_runner.commit_or_rollback("Could not update alias in DSDB")

        return
コード例 #4
0
ファイル: add_srv_record.py プロジェクト: jrha/aquilon
    def render(self, session, service, protocol, dns_domain, priority, weight,
               target, port, dns_environment, comments, **kwargs):
        dbdns_env = DnsEnvironment.get_unique_or_default(session,
                                                         dns_environment)
        dbdns_domain = DnsDomain.get_unique(session, dns_domain, compel=True)
        if dbdns_domain.restricted:
            raise ArgumentError("{0} is restricted, SRV records are not allowed."
                                .format(dbdns_domain))

        # TODO: we could try looking up the port based on the service, but there
        # are some caveats:
        # - the protocol name used in SRV record may not match the name used in
        #   /etc/services
        # - socket.getservent() may return bogus information (like it does for
        #   e.g. 'kerberos')

        service = service.strip().lower()
        target = target.strip().lower()

        dbtarget = Fqdn.get_unique(session, target, compel=True)
        dbsrv_rec = SrvRecord(service=service, protocol=protocol,
                              priority=priority, weight=weight, target=dbtarget,
                              port=port, dns_domain=dbdns_domain,
                              dns_environment=dbdns_env, comments=comments)
        session.add(dbsrv_rec)

        session.flush()

        return
コード例 #5
0
ファイル: show_dynamic_range.py プロジェクト: jrha/aquilon
    def render(self, session, fqdn, ip, dns_environment, **arguments):
        dbdns_env = DnsEnvironment.get_unique_or_default(session,
                                                         dns_environment)
        if fqdn:
            dbdns_rec = DynamicStub.get_unique(session, fqdn=fqdn,
                                               dns_environment=dbdns_env,
                                               compel=True)
            dbnetwork = dbdns_rec.network
            ip = dbdns_rec.ip
        if ip:
            dbnetwork = get_net_id_from_ip(session, ip)

        all_stubs = {}
        q = session.query(DynamicStub.ip)
        q = q.filter_by(network=dbnetwork)
        for stub in q:
            all_stubs[int(stub.ip)] = True

        start = int(ip)
        while start > int(dbnetwork.ip) and start - 1 in all_stubs:
            start = start - 1

        end = int(ip)
        while end < int(dbnetwork.broadcast) and end + 1 in all_stubs:
            end = end + 1

        return DynamicRange(dbnetwork, IPv4Address(start), IPv4Address(end))
コード例 #6
0
ファイル: update_alias.py プロジェクト: jrha/aquilon
    def render(self, session, logger, fqdn, dns_environment, target, comments,
               **kwargs):
        dbdns_env = DnsEnvironment.get_unique_or_default(session,
                                                         dns_environment)
        dbalias = Alias.get_unique(session, fqdn=fqdn,
                                   dns_environment=dbdns_env, compel=True)

        old_target_fqdn = str(dbalias.target.fqdn)
        old_comments = dbalias.comments

        if target:
            old_target = dbalias.target
            dbalias.target = create_target_if_needed(session, logger,
                                                     target, dbdns_env)
            if dbalias.target != old_target:
                delete_target_if_needed(session, old_target)

        if comments is not None:
            dbalias.comments = comments

        session.flush()

        if dbdns_env.is_default and dbalias.fqdn.dns_domain.name == "ms.com":
            dsdb_runner = DSDBRunner(logger=logger)
            dsdb_runner.update_alias(fqdn, dbalias.target.fqdn,
                                     dbalias.comments, old_target_fqdn,
                                     old_comments)
            dsdb_runner.commit_or_rollback("Could not update alias in DSDB")

        return
コード例 #7
0
ファイル: del_dns_environment.py プロジェクト: jrha/aquilon
    def render(self, session, dns_environment, **arguments):
        db_dnsenv = DnsEnvironment.get_unique(session, dns_environment,
                                              compel=True)

        if db_dnsenv.is_default:
            raise ArgumentError("{0} is the default DNS environment, "
                                "therefore it cannot be deleted."
                                .format(db_dnsenv))
        q = session.query(Fqdn)
        q = q.filter_by(dns_environment=db_dnsenv)
        if q.first():
            raise ArgumentError("{0} is still in use by DNS records, and "
                                "cannot be deleted.".format(db_dnsenv))

        q = session.query(RouterAddress)
        q = q.filter_by(dns_environment=db_dnsenv)
        if q.first():
            raise ArgumentError("{0} is still in use by routers, and "
                                "cannot be deleted.".format(db_dnsenv))

        q = session.query(AddressAssignment)
        q = q.filter_by(dns_environment=db_dnsenv)
        if q.first():
            raise ArgumentError("{0} is still in use by address assignments, "
                                "and cannot be deleted.".format(db_dnsenv))

        session.delete(db_dnsenv)
        session.flush()

        return
コード例 #8
0
ファイル: show_fqdn_fqdn.py プロジェクト: jrha/aquilon
 def render(self, session, fqdn, dns_environment, **kwargs):
     self.deprecated_command("The show_fqdn command is deprecated.  Please "
                             "use search_dns instead.", **kwargs)
     dbdns_env = DnsEnvironment.get_unique_or_default(session, dns_environment)
     dbfqdn = Fqdn.get_unique(session, fqdn=fqdn, dns_environment=dbdns_env,
                              compel=True)
     q = session.query(DnsRecord)
     q = q.filter_by(fqdn=dbfqdn)
     return q.all()
コード例 #9
0
ファイル: bind_server.py プロジェクト: piojo/aquilon
def lookup_target(session, plenaries, hostname, ip, cluster, resourcegroup,
                  service_address, alias):
    """
    Check the parameters of the server providing a given service

    Look for potential conflicts, and return a dict that is suitable to be
    passed to either the constructor of ServiceInstanceServer, or to the
    find_server() function.
    """

    params = {}

    if cluster and hostname:
        raise ArgumentError("Only one of --cluster and --hostname may be "
                            "specified.")

    if alias:
        dbdns_env = DnsEnvironment.get_unique_or_default(session)
        dbdns_rec = Alias.get_unique(session, fqdn=alias,
                                     dns_environment=dbdns_env, compel=True)
        params["alias"] = dbdns_rec

    if hostname:
        params["host"] = hostname_to_host(session, hostname)
        plenaries.append(Plenary.get_plenary(params["host"]))
    if cluster:
        params["cluster"] = Cluster.get_unique(session, cluster, compel=True)
        plenaries.append(Plenary.get_plenary(params["cluster"]))

    if service_address:
        # TODO: calling get_resource_holder() means doing redundant DB lookups
        # TODO: it would be nice to also accept an FQDN for the service address,
        # to be consistent with the usage of the --service_address option in
        # add_service_address/del_service_address
        holder = get_resource_holder(session, hostname=hostname,
                                     cluster=cluster,
                                     resgroup=resourcegroup, compel=True)

        dbsrv_addr = ServiceAddress.get_unique(session,
                                               name=service_address,
                                               holder=holder, compel=True)
        params["service_address"] = dbsrv_addr
    elif ip:
        for addr in params["host"].hardware_entity.all_addresses():
            if ip != addr.ip:
                continue

            if addr.service_address:
                params["service_address"] = addr.service_address
            else:
                params["address_assignment"] = addr
            break

    return params
コード例 #10
0
def get_net_dns_env(session, network_environment=None, dns_environment=None):
    dbnet_env = NetworkEnvironment.get_unique_or_default(
        session, network_environment)
    if dns_environment:
        dbdns_env = DnsEnvironment.get_unique(session,
                                              dns_environment,
                                              compel=True)
    else:
        dbdns_env = dbnet_env.dns_environment

    return (dbnet_env, dbdns_env)
コード例 #11
0
ファイル: show_fqdn_all.py プロジェクト: jrha/aquilon
 def render(self, session, dns_environment, **arguments):
     self.deprecated_command("The show_fqdn command is deprecated.  Please "
                             "use search_dns instead.", **arguments)
     dbdns_env = DnsEnvironment.get_unique_or_default(session,
                                                      dns_environment)
     q = session.query(Fqdn)
     q = q.filter_by(dns_environment=dbdns_env)
     q = q.join(DnsDomain)
     q = q.options(contains_eager("dns_domain"))
     q = q.order_by(DnsDomain.name, Fqdn.name)
     return StringList(q.all())
コード例 #12
0
ファイル: network_environment.py プロジェクト: piojo/aquilon
def get_net_dns_env(session, network_environment=None,
                    dns_environment=None):
    dbnet_env = NetworkEnvironment.get_unique_or_default(session,
                                                         network_environment)
    if dns_environment:
        dbdns_env = DnsEnvironment.get_unique(session, dns_environment,
                                              compel=True)
    else:
        dbdns_env = dbnet_env.dns_environment

    return (dbnet_env, dbdns_env)
コード例 #13
0
 def render(self, session, dns_environment, **arguments):
     self.deprecated_command(
         "The show_fqdn command is deprecated.  Please "
         "use search_dns instead.", **arguments)
     dbdns_env = DnsEnvironment.get_unique_or_default(
         session, dns_environment)
     q = session.query(Fqdn)
     q = q.filter_by(dns_environment=dbdns_env)
     q = q.join(DnsDomain)
     q = q.options(contains_eager("dns_domain"))
     q = q.order_by(DnsDomain.name, Fqdn.name)
     return StringList(q.all())
コード例 #14
0
 def render(self, session, fqdn, dns_environment, **kwargs):
     self.deprecated_command(
         "The show_fqdn command is deprecated.  Please "
         "use search_dns instead.", **kwargs)
     dbdns_env = DnsEnvironment.get_unique_or_default(
         session, dns_environment)
     dbfqdn = Fqdn.get_unique(session,
                              fqdn=fqdn,
                              dns_environment=dbdns_env,
                              compel=True)
     q = session.query(DnsRecord)
     q = q.filter_by(fqdn=dbfqdn)
     return q.all()
コード例 #15
0
ファイル: fqdn.py プロジェクト: jrha/aquilon
    def get_unique(cls, session, fqdn=None, dns_environment=None, name=None,
                   dns_domain=None, **kwargs):
        if fqdn:
            if name or dns_domain:  # pragma: no cover
                raise TypeError("fqdn and name/dns_domain should not be mixed")
            (name, dns_domain) = parse_fqdn(session, fqdn)

        if not isinstance(dns_environment, DnsEnvironment):
            dns_environment = DnsEnvironment.get_unique_or_default(session,
                                                                   dns_environment)
        return super(Fqdn, cls).get_unique(session, name=name,
                                           dns_domain=dns_domain,
                                           dns_environment=dns_environment,
                                           **kwargs)
コード例 #16
0
    def get_unique(cls,
                   session,
                   fqdn=None,
                   name=None,
                   dns_domain=None,
                   dns_environment=None,
                   compel=False,
                   preclude=False,
                   **kwargs):
        # Proxy FQDN lookup to the Fqdn class
        if not fqdn or not isinstance(fqdn, Fqdn):
            if not isinstance(dns_environment, DnsEnvironment):
                dns_environment = DnsEnvironment.get_unique_or_default(
                    session, dns_environment)
            if fqdn:
                if name or dns_domain:  # pragma: no cover
                    raise TypeError("fqdn and name/dns_domain cannot be mixed")
                (name, dns_domain) = parse_fqdn(session, fqdn)
            try:
                # Do not pass preclude=True to Fqdn
                fqdn = Fqdn.get_unique(session,
                                       name=name,
                                       dns_domain=dns_domain,
                                       dns_environment=dns_environment,
                                       compel=compel)
            except NotFoundException:
                # Replace the "Fqdn ... not found" message with a more user
                # friendly one
                msg = "%s %s.%s, %s not found." % (
                    cls._get_class_label(), name, dns_domain,
                    format(dns_environment, "l"))
                raise NotFoundException(msg)
            if not fqdn:
                return None

        # We already have the FQDN, no need to load it again
        if "query_options" not in kwargs:
            kwargs["query_options"] = [lazyload("fqdn")]

        result = super(DnsRecord, cls).get_unique(session,
                                                  fqdn=fqdn,
                                                  compel=compel,
                                                  preclude=preclude,
                                                  **kwargs)
        if result:
            # Make sure not to load the relation again if we already know its
            # value
            set_committed_value(result, 'fqdn', fqdn)
        return result
コード例 #17
0
ファイル: fqdn.py プロジェクト: jrha/aquilon
    def __init__(self, session=None, name=None, dns_domain=None, fqdn=None,
                 dns_environment=None, ignore_name_check=False, **kwargs):
        if fqdn:
            if name or dns_domain:  # pragma: no cover
                raise TypeError("fqdn and name/dns_domain should not be mixed")
            self._check_session(session)
            (name, dns_domain) = parse_fqdn(session, fqdn)

        self.check_name(name, dns_domain, ignore_name_check)

        if not isinstance(dns_environment, DnsEnvironment):
            self._check_session(session)
            dns_environment = DnsEnvironment.get_unique_or_default(session,
                                                                   dns_environment)

        super(Fqdn, self).__init__(name=name, dns_domain=dns_domain,
                                   dns_environment=dns_environment, **kwargs)
コード例 #18
0
ファイル: del_alias.py プロジェクト: stdweird/aquilon
    def render(self, session, logger, fqdn, dns_environment, **kwargs):
        dbdns_env = DnsEnvironment.get_unique_or_default(session, dns_environment)
        dbdns_rec = Alias.get_unique(session, fqdn=fqdn, dns_environment=dbdns_env, compel=True)
        domain = dbdns_rec.fqdn.dns_domain.name

        old_target_fqdn = str(dbdns_rec.target)
        old_comments = dbdns_rec.comments
        target_is_restricted = dbdns_rec.target.dns_domain.restricted
        delete_dns_record(dbdns_rec)

        session.flush()

        if dbdns_env.is_default and domain == "ms.com" and not target_is_restricted:
            dsdb_runner = DSDBRunner(logger=logger)
            dsdb_runner.del_alias(fqdn, old_target_fqdn, old_comments)
            dsdb_runner.commit_or_rollback("Could not delete alias from DSDB")

        return
コード例 #19
0
ファイル: fqdn.py プロジェクト: jrha/aquilon
    def get_or_create(cls, session, dns_environment=None, preclude=False,
                      ignore_name_check=False, query_options=None, **kwargs):
        fqdn = cls.get_unique(session, dns_environment=dns_environment,
                              query_options=query_options, **kwargs)
        if fqdn:
            if preclude:
                _raise_custom(preclude, ArgumentError,
                              "{0} already exists.".format(fqdn))
            return fqdn

        if not isinstance(dns_environment, DnsEnvironment):
            dns_environment = DnsEnvironment.get_unique_or_default(session,
                                                                   dns_environment)

        fqdn = cls(session=session, dns_environment=dns_environment,
                   ignore_name_check=ignore_name_check, **kwargs)
        session.add(fqdn)
        return fqdn
コード例 #20
0
ファイル: update_alias.py プロジェクト: piojo/aquilon
    def render(self, session, logger, fqdn, dns_environment, target, comments,
               **kwargs):
        dbdns_env = DnsEnvironment.get_unique_or_default(session,
                                                         dns_environment)
        dbalias = Alias.get_unique(session, fqdn=fqdn,
                                   dns_environment=dbdns_env, compel=True)

        old_target_fqdn = str(dbalias.target.fqdn)
        old_comments = dbalias.comments

        if target:
            old_target = dbalias.target
            dbalias.target = create_target_if_needed(session, logger,
                                                     target, dbdns_env)

            # TODO: at some day we should verify that the new target is also
            # bound as a server, and modify the ServiceInstanceServer bindings
            # accordingly
            for srv in dbalias.services_provided:
                if srv.host or srv.cluster:
                    provider = srv.host or srv.cluster
                    logger.client_info("Warning: {0} provides {1:l}, and is "
                                       "bound to {2:l}. Updating the target of "
                                       "the alias may leave that server "
                                       "binding in an inconsistent state."
                                       .format(dbalias, srv.service_instance,
                                               provider))

            if dbalias.target != old_target:
                delete_target_if_needed(session, old_target)

        if comments is not None:
            dbalias.comments = comments

        session.flush()

        if dbdns_env.is_default and dbalias.fqdn.dns_domain.name == "ms.com":
            dsdb_runner = DSDBRunner(logger=logger)
            dsdb_runner.update_alias(fqdn, dbalias.target.fqdn,
                                     dbalias.comments, old_target_fqdn,
                                     old_comments)
            dsdb_runner.commit_or_rollback("Could not update alias in DSDB")

        return
コード例 #21
0
ファイル: show_dns_record.py プロジェクト: ned21/aquilon
    def render(self,
               session,
               fqdn,
               record_type,
               dns_environment,
               network_environment=None,
               **arguments):

        if network_environment:
            if not isinstance(network_environment, NetworkEnvironment):
                network_environment = NetworkEnvironment.get_unique_or_default(
                    session, network_environment)
            if not dns_environment:
                dns_environment = network_environment.dns_environment

        dbdns_env = DnsEnvironment.get_unique_or_default(
            session, dns_environment)
        # No compel here. query(DnsRecord).filter_by(fqdn=None) will fail if the
        # FQDN is invalid, and that will give a better error message.
        dbfqdn = Fqdn.get_unique(session, fqdn=fqdn, dns_environment=dbdns_env)

        if record_type:
            if record_type in DNS_RRTYPE_MAP:
                cls = DNS_RRTYPE_MAP[record_type]
            else:
                cls = DnsRecord.polymorphic_subclass(
                    record_type, "Unknown DNS record type")
        else:
            cls = DnsRecord

        # We want to query(ARecord) instead of
        # query(DnsRecord).filter_by(record_type='a_record'), because the former
        # works for DynamicStub as well
        q = session.query(cls)
        if cls == DnsRecord:
            q = q.with_polymorphic('*')
        q = q.filter_by(fqdn=dbfqdn)
        result = q.all()
        if not result:
            raise NotFoundException("%s %s not found." %
                                    (cls._get_class_label(), fqdn))
        return result
コード例 #22
0
    def get_unique(cls,
                   session,
                   fqdn=None,
                   dns_environment=None,
                   name=None,
                   dns_domain=None,
                   **kwargs):
        if fqdn:
            if name or dns_domain:  # pragma: no cover
                raise TypeError("fqdn and name/dns_domain should not be mixed")
            (name, dns_domain) = parse_fqdn(session, fqdn)

        if not isinstance(dns_environment, DnsEnvironment):
            dns_environment = DnsEnvironment.get_unique_or_default(
                session, dns_environment)
        return super(Fqdn, cls).get_unique(session,
                                           name=name,
                                           dns_domain=dns_domain,
                                           dns_environment=dns_environment,
                                           **kwargs)
コード例 #23
0
ファイル: add_alias.py プロジェクト: jrha/aquilon
    def render(self, session, logger, fqdn, dns_environment, target, comments,
               **kwargs):
        dbdns_env = DnsEnvironment.get_unique_or_default(session,
                                                         dns_environment)

        dbfqdn = Fqdn.get_or_create(session, dns_environment=dbdns_env,
                                    fqdn=fqdn)

        if dbfqdn.dns_domain.restricted:
            raise ArgumentError("{0} is restricted, aliases are not allowed."
                                .format(dbfqdn.dns_domain))

        DnsRecord.get_unique(session, fqdn=dbfqdn, preclude=True)

        dbtarget = create_target_if_needed(session, logger, target, dbdns_env)
        try:
            db_record = Alias(fqdn=dbfqdn, target=dbtarget, comments=comments)
            session.add(db_record)
        except ValueError, err:
            raise ArgumentError(err.message)
コード例 #24
0
ファイル: show_srv_record.py プロジェクト: jrha/aquilon
    def render(self, session, service, protocol, dns_domain, dns_environment,
               **kwargs):
        dbdns_env = DnsEnvironment.get_unique_or_default(session,
                                                         dns_environment)
        dbdns_domain = DnsDomain.get_unique(session, dns_domain, compel=True)

        name = "_%s._%s" % (service.strip().lower(), protocol.strip().lower())

        q = session.query(SrvRecord)
        q = q.join((Fqdn, SrvRecord.fqdn_id == Fqdn.id))
        q = q.options(contains_eager('fqdn'))
        q = q.filter_by(dns_domain=dbdns_domain)
        q = q.filter_by(name=name)
        q = q.filter_by(dns_environment=dbdns_env)
        result = q.all()
        if not result:
            raise NotFoundException("%s for service %s, protocol %s in DNS "
                                    "domain %s not found." %
                                    (SrvRecord._get_class_label(), service,
                                     protocol, dns_domain))
        return result
コード例 #25
0
ファイル: show_srv_record.py プロジェクト: ned21/aquilon
    def render(self, session, service, protocol, dns_domain, dns_environment,
               **kwargs):
        dbdns_env = DnsEnvironment.get_unique_or_default(
            session, dns_environment)
        dbdns_domain = DnsDomain.get_unique(session, dns_domain, compel=True)

        name = "_%s._%s" % (service.strip().lower(), protocol.strip().lower())

        q = session.query(SrvRecord)
        q = q.join((Fqdn, SrvRecord.fqdn_id == Fqdn.id))
        q = q.options(contains_eager('fqdn'))
        q = q.filter_by(dns_domain=dbdns_domain)
        q = q.filter_by(name=name)
        q = q.filter_by(dns_environment=dbdns_env)
        result = q.all()
        if not result:
            raise NotFoundException(
                "%s for service %s, protocol %s in DNS "
                "domain %s not found." %
                (SrvRecord._get_class_label(), service, protocol, dns_domain))
        return result
コード例 #26
0
ファイル: dns_record.py プロジェクト: piojo/aquilon
    def get_unique(cls, session, fqdn=None, name=None, dns_domain=None,
                   dns_environment=None, compel=False, preclude=False, **kwargs):
        # Proxy FQDN lookup to the Fqdn class
        if not fqdn or not isinstance(fqdn, Fqdn):
            if not isinstance(dns_environment, DnsEnvironment):
                dns_environment = DnsEnvironment.get_unique_or_default(session,
                                                                       dns_environment)
            if fqdn:
                if name or dns_domain:  # pragma: no cover
                    raise TypeError("fqdn and name/dns_domain cannot be mixed")
                (name, dns_domain) = parse_fqdn(session, fqdn)
            try:
                # Do not pass preclude=True to Fqdn
                fqdn = Fqdn.get_unique(session, name=name,
                                       dns_domain=dns_domain,
                                       dns_environment=dns_environment,
                                       compel=compel)
            except NotFoundException:
                # Replace the "Fqdn ... not found" message with a more user
                # friendly one
                msg = "%s %s.%s, %s not found." % (cls._get_class_label(),
                                                   name, dns_domain,
                                                   format(dns_environment, "l"))
                raise NotFoundException(msg)
            if not fqdn:
                return None

        # We already have the FQDN, no need to load it again
        if "query_options" not in kwargs:
            kwargs["query_options"] = [lazyload("fqdn")]

        result = super(DnsRecord, cls).get_unique(session, fqdn=fqdn,
                                                  compel=compel,
                                                  preclude=preclude, **kwargs)
        if result:
            # Make sure not to load the relation again if we already know its
            # value
            set_committed_value(result, 'fqdn', fqdn)
        return result
コード例 #27
0
    def render(self, session, network_environment, dns_environment, comments,
               **arguments):
        validate_nlist_key("network environment", network_environment)
        NetworkEnvironment.get_unique(session, network_environment,
                                      preclude=True)
        dbdns_env = DnsEnvironment.get_unique(session, dns_environment,
                                              compel=True)

        # Currently input.xml lists --building only, but that may change
        location = get_location(session, **arguments)

        dbnet_env = NetworkEnvironment(name=network_environment,
                                       dns_environment=dbdns_env,
                                       location=location, comments=comments)

        if dbdns_env.is_default != dbnet_env.is_default:
            raise ArgumentError("Only the default network environment may be "
                                "associated with the default DNS environment.")

        session.add(dbnet_env)
        session.flush()
        return
コード例 #28
0
ファイル: system.py プロジェクト: jrha/aquilon
def search_system_query(session, dns_record_type=DnsRecord, **kwargs):
    q = session.query(dns_record_type)
    # Outer-join in all the subclasses so that each access of
    # system doesn't (necessarily) issue another query.
    if dns_record_type is DnsRecord:
        q = q.with_polymorphic('*')

    dbdns_env = DnsEnvironment.get_unique_or_default(session,
                                                     kwargs.get("dns_environment",
                                                                None))
    q = q.join((Fqdn, DnsRecord.fqdn_id == Fqdn.id))
    q = q.filter_by(dns_environment=dbdns_env)
    q = q.options(contains_eager('fqdn'))
    if kwargs.get('fqdn', None):
        (short, dbdns_domain) = parse_fqdn(session, kwargs['fqdn'])
        q = q.filter_by(name=short, dns_domain=dbdns_domain)
    if kwargs.get('dns_domain', None):
        dbdns_domain = DnsDomain.get_unique(session, kwargs['dns_domain'],
                                            compel=True)
        q = q.filter_by(dns_domain=dbdns_domain)
    if kwargs.get('shortname', None):
        q = q.filter_by(name=kwargs['shortname'])
    q = q.reset_joinpoint()

    if kwargs.get('ip', None):
        q = q.filter(ARecord.ip == kwargs['ip'])
    if kwargs.get('networkip', None):
        net_env = kwargs.get('network_environment', None)
        dbnet_env = NetworkEnvironment.get_unique_or_default(session, net_env)
        dbnetwork = get_network_byip(session, kwargs['networkip'], dbnet_env)
        q = q.filter(ARecord.network == dbnetwork)
    if kwargs.get('mac', None):
        raise UnimplementedError("search_system --mac is no longer supported, "
                                 "try search_hardware.")
    if kwargs.get('type', None):
        # Deprecated... remove if it becomes a problem.
        type_arg = kwargs['type'].strip().lower()
        q = q.filter_by(dns_record_type=type_arg)
    return q
コード例 #29
0
ファイル: del_alias.py プロジェクト: ned21/aquilon
    def render(self, session, logger, fqdn, dns_environment, **kwargs):
        dbdns_env = DnsEnvironment.get_unique_or_default(
            session, dns_environment)
        dbdns_rec = Alias.get_unique(session,
                                     fqdn=fqdn,
                                     dns_environment=dbdns_env,
                                     compel=True)
        domain = dbdns_rec.fqdn.dns_domain.name

        old_target_fqdn = str(dbdns_rec.target)
        old_comments = dbdns_rec.comments
        target_is_restricted = dbdns_rec.target.dns_domain.restricted
        delete_dns_record(dbdns_rec)

        session.flush()

        if dbdns_env.is_default and domain == "ms.com" and not target_is_restricted:
            dsdb_runner = DSDBRunner(logger=logger)
            dsdb_runner.del_alias(fqdn, old_target_fqdn, old_comments)
            dsdb_runner.commit_or_rollback("Could not delete alias from DSDB")

        return
コード例 #30
0
ファイル: add_alias.py プロジェクト: ned21/aquilon
    def render(self, session, logger, fqdn, dns_environment, target, comments,
               **kwargs):
        dbdns_env = DnsEnvironment.get_unique_or_default(
            session, dns_environment)

        dbfqdn = Fqdn.get_or_create(session,
                                    dns_environment=dbdns_env,
                                    fqdn=fqdn)

        if dbfqdn.dns_domain.restricted:
            raise ArgumentError(
                "{0} is restricted, aliases are not allowed.".format(
                    dbfqdn.dns_domain))

        DnsRecord.get_unique(session, fqdn=dbfqdn, preclude=True)

        dbtarget = create_target_if_needed(session, logger, target, dbdns_env)
        try:
            db_record = Alias(fqdn=dbfqdn, target=dbtarget, comments=comments)
            session.add(db_record)
        except ValueError, err:
            raise ArgumentError(err.message)
コード例 #31
0
ファイル: show_dns_record.py プロジェクト: piojo/aquilon
    def render(self, session, fqdn, record_type, dns_environment,
               network_environment=None, **arguments):

        if network_environment:
            if not isinstance(network_environment, NetworkEnvironment):
                network_environment = NetworkEnvironment.get_unique_or_default(session,
                                                                               network_environment)
            if not dns_environment:
                dns_environment = network_environment.dns_environment

        dbdns_env = DnsEnvironment.get_unique_or_default(session,
                                                         dns_environment)
        # No compel here. query(DnsRecord).filter_by(fqdn=None) will fail if the
        # FQDN is invalid, and that will give a better error message.
        dbfqdn = Fqdn.get_unique(session, fqdn=fqdn,
                                 dns_environment=dbdns_env)

        if record_type:
            if record_type in DNS_RRTYPE_MAP:
                cls = DNS_RRTYPE_MAP[record_type]
            else:
                cls = DnsRecord.polymorphic_subclass(record_type,
                                                     "Unknown DNS record type")
        else:
            cls = DnsRecord

        # We want to query(ARecord) instead of
        # query(DnsRecord).filter_by(record_type='a_record'), because the former
        # works for DynamicStub as well
        q = session.query(cls)
        if cls == DnsRecord:
            q = q.with_polymorphic('*')
        q = q.filter_by(fqdn=dbfqdn)
        result = q.all()
        if not result:
            raise NotFoundException("%s %s not found." %
                                    (cls._get_class_label(), fqdn))
        return result
コード例 #32
0
ファイル: dump_dns.py プロジェクト: jrha/aquilon
    def render(self, session, dns_domain, dns_environment, **arguments):
        dbdns_env = DnsEnvironment.get_unique_or_default(session,
                                                         dns_environment)
        if dns_domain:
            dbdns_domain = DnsDomain.get_unique(session, dns_domain,
                                                compel=True)
        else:
            dbdns_domain = None

        q = session.query(DnsRecord)
        q = q.with_polymorphic('*')
        q = q.join((Fqdn, DnsRecord.fqdn_id == Fqdn.id))
        q = q.options(contains_eager('fqdn'))
        q = q.filter_by(dns_environment=dbdns_env)
        if dbdns_domain:
            q = q.filter_by(dns_domain=dbdns_domain)
            dns_domains = [dbdns_domain]
        else:
            # Preload DNS domains, and keep a reference to prevent them being
            # evicted from the session's cache
            dns_domains = session.query(DnsDomain).all()

        return DnsDump(q.all(), dns_domains)
コード例 #33
0
ファイル: qip.py プロジェクト: jrha/aquilon
    def __init__(self, session, logger, dbbuilding, dryrun, incremental):
        self.session = session
        self.logger = logger
        self.building = dbbuilding
        self.dryrun = dryrun
        self.incremental = incremental

        # Synchronize the internal environment only
        self.net_env = NetworkEnvironment.get_unique_or_default(session)

        self.errors = []

        self.dns_env = DnsEnvironment.get_unique_or_default(session)

        # Cache building and bunker information. Load all buildings even if
        # we're interested in only one, so we can verify subnetdata.txt
        self.buildings = {}
        for item in session.query(Building):
            self.buildings[item.name] = item
        self.bunkers = {}
        for item in session.query(Bunker):
            self.bunkers[item.name] = item

        # Used to limit the number of warnings
        self.unknown_syslocs = set()

        # Load existing networks. We have to load all, otherwise we won't be
        # able to fix networks with wrong location
        self.aqnetworks = {}
        q = session.query(Network)
        q = q.filter_by(network_environment=self.net_env)
        q = q.options(subqueryload("routers"))
        for item in q:
            self.aqnetworks[item.ip] = item

        # Save how many networks we had initially
        self.networks_before = len(self.aqnetworks.keys())
コード例 #34
0
    def __init__(self, session, logger, dbbuilding, dryrun, incremental):
        self.session = session
        self.logger = logger
        self.building = dbbuilding
        self.dryrun = dryrun
        self.incremental = incremental

        # Synchronize the internal environment only
        self.net_env = NetworkEnvironment.get_unique_or_default(session)

        self.errors = []

        self.dns_env = DnsEnvironment.get_unique_or_default(session)

        # Cache building and bunker information. Load all buildings even if
        # we're interested in only one, so we can verify subnetdata.txt
        self.buildings = {}
        for item in session.query(Building):
            self.buildings[item.name] = item
        self.bunkers = {}
        for item in session.query(Bunker):
            self.bunkers[item.name] = item

        # Used to limit the number of warnings
        self.unknown_syslocs = set()

        # Load existing networks. We have to load all, otherwise we won't be
        # able to fix networks with wrong location
        self.aqnetworks = {}
        q = session.query(Network)
        q = q.filter_by(network_environment=self.net_env)
        q = q.options(subqueryload("routers"))
        for item in q:
            self.aqnetworks[item.ip] = item

        # Save how many networks we had initially
        self.networks_before = len(self.aqnetworks.keys())
コード例 #35
0
ファイル: dump_dns.py プロジェクト: ned21/aquilon
    def render(self, session, dns_domain, dns_environment, **arguments):
        dbdns_env = DnsEnvironment.get_unique_or_default(
            session, dns_environment)
        if dns_domain:
            dbdns_domain = DnsDomain.get_unique(session,
                                                dns_domain,
                                                compel=True)
        else:
            dbdns_domain = None

        q = session.query(DnsRecord)
        q = q.with_polymorphic('*')
        q = q.join((Fqdn, DnsRecord.fqdn_id == Fqdn.id))
        q = q.options(contains_eager('fqdn'))
        q = q.filter_by(dns_environment=dbdns_env)
        if dbdns_domain:
            q = q.filter_by(dns_domain=dbdns_domain)
            dns_domains = [dbdns_domain]
        else:
            # Preload DNS domains, and keep a reference to prevent them being
            # evicted from the session's cache
            dns_domains = session.query(DnsDomain).all()

        return DnsDump(q.all(), dns_domains)
コード例 #36
0
ファイル: test_primary_name.py プロジェクト: jrha/aquilon
def setup():
    dmn = DnsDomain.get_unique(sess, DNS_DOMAIN_NAME, compel=True)
    assert isinstance(dmn, DnsDomain), 'No ms.com domain in %s' % func_name()

    intrnl = DnsEnvironment.get_unique(sess, DNS_ENV, compel=True)
    assert isinstance(dmn, DnsDomain), 'No internal env in %s' % func_name()
コード例 #37
0
ファイル: dns.py プロジェクト: ned21/aquilon
def grab_address(session,
                 fqdn,
                 ip,
                 network_environment=None,
                 dns_environment=None,
                 comments=None,
                 allow_restricted_domain=False,
                 allow_multi=False,
                 allow_reserved=False,
                 relaxed=False,
                 preclude=False):
    """
    Take ownership of an address.

    This is a bit complicated because due to DNS propagation delays, we want to
    allow users to pre-define a DNS address and then assign the address to a
    host later.

    Parameters:
        session: SQLA session handle
        fqdn: the name to allocate/take over
        ip: the IP address to allocate/take over
        network_environment: where the IP address lives
        dns_enviromnent: where the FQDN lives
        comments: any comments to attach to the DNS record if it is created as new
        allow_restricted_domain: if True, adding entries to restricted DNS
            domains is allowed, otherwise it is denied. Default is False.
        allow_multi: if True, allow the same FQDN to be added multiple times with
            different IP addresses. Deault is False.
        allow_reserved: if True, allow creating a ReservedName instead of an
            ARecord if no IP address was specified. Default is False.
        preclude: if True, forbid taking over an existing DNS record, even if it
            is not referenced by any AddressAssignment records. Default is
            False.
    """
    if not isinstance(network_environment, NetworkEnvironment):
        network_environment = NetworkEnvironment.get_unique_or_default(
            session, network_environment)
    if not dns_environment:
        dns_environment = network_environment.dns_environment
    elif not isinstance(dns_environment, DnsEnvironment):
        dns_environment = DnsEnvironment.get_unique(session,
                                                    dns_environment,
                                                    compel=True)

    # Non-default DNS environments may contain anything, but we want to keep
    # the internal environment clean
    if dns_environment.is_default and not network_environment.is_default:
        raise ArgumentError("Entering external IP addresses to the "
                            "internal DNS environment is not allowed.")

    short, dbdns_domain = parse_fqdn(session, fqdn)

    # Lock the domain to prevent adding/deleting records while we're checking
    # FQDN etc. availability
    dbdns_domain.lock_row()

    if dbdns_domain.restricted and not allow_restricted_domain:
        raise ArgumentError("{0} is restricted, adding extra addresses "
                            "is not allowed.".format(dbdns_domain))

    dbfqdn = Fqdn.get_or_create(session,
                                dns_environment=dns_environment,
                                name=short,
                                dns_domain=dbdns_domain,
                                query_options=[joinedload('dns_records')])

    existing_record = None
    newly_created = False

    if ip:
        dbnetwork = get_net_id_from_ip(session, ip, network_environment)
        check_ip_restrictions(dbnetwork, ip, relaxed=relaxed)

        dbnetwork.lock_row()

        # No filtering on DNS environment. If an address is dynamic in one
        # environment, it should not be considered static in a different
        # environment.
        q = session.query(DynamicStub)
        q = q.filter_by(network=dbnetwork)
        q = q.filter_by(ip=ip)
        dbdns_rec = q.first()
        _forbid_dyndns(dbdns_rec)

        # Verify that no other record uses the same IP address, this time taking
        # the DNS environemt into consideration.
        # While the DNS would allow different A records to point to the same IP
        # address, the current user expectation is that creating a DNS entry
        # also counts as a reservation, so we can not allow this use case. If we
        # want to implement such a feature later, the best way would be to
        # subclass Alias and let that subclass emit an A record instead of a
        # CNAME when the dump_dns command is called.
        q = session.query(ARecord)
        q = q.filter_by(network=dbnetwork)
        q = q.filter_by(ip=ip)
        q = q.join(ARecord.fqdn)
        q = q.filter_by(dns_environment=dns_environment)
        dbrecords = q.all()
        if dbrecords and len(dbrecords) > 1:  # pragma: no cover
            # We're just trying to make sure this never happens
            raise AquilonError(
                "IP address %s is referenced by multiple "
                "DNS records: %s" %
                (ip, ", ".join([format(rec, "a") for rec in dbrecords])))
        if dbrecords and dbrecords[0].fqdn != dbfqdn:
            raise ArgumentError(
                "IP address {0} is already in use by {1:l}.".format(
                    ip, dbrecords[0]))

        # Check if the name is used already
        for dbdns_rec in dbfqdn.dns_records:
            if isinstance(dbdns_rec, ARecord):
                _forbid_dyndns(dbdns_rec)
                _check_netenv_compat(dbdns_rec, network_environment)
                if dbdns_rec.ip == ip and dbdns_rec.network == dbnetwork:
                    existing_record = dbdns_rec
                elif not allow_multi:
                    raise ArgumentError(
                        "{0} points to a different IP address.".format(
                            dbdns_rec))

            elif isinstance(dbdns_rec, ReservedName):
                existing_record = convert_reserved_to_arecord(
                    session, dbdns_rec, dbnetwork, ip)
                newly_created = True
            else:
                # Exclude aliases etc.
                raise ArgumentError(
                    "{0} cannot be used for address assignment.".format(
                        dbdns_rec))

        if not existing_record:
            existing_record = ARecord(fqdn=dbfqdn,
                                      ip=ip,
                                      network=dbnetwork,
                                      comments=comments)
            session.add(existing_record)
            newly_created = True
    else:
        if not dbfqdn.dns_records:
            # There's no IP, and the name did not exist before. Create a
            # reservation, but only if the caller allowed that use case.
            if not allow_reserved:
                raise ArgumentError("DNS Record %s does not exist." % dbfqdn)

            existing_record = ReservedName(fqdn=dbfqdn, comments=comments)
            newly_created = True
        else:
            # There's no IP, but the name is already in use. We need a single IP
            # address.
            if len(dbfqdn.dns_records) > 1:
                raise ArgumentError(
                    "{0} does not resolve to a single IP address.".format(
                        dbfqdn))

            existing_record = dbfqdn.dns_records[0]
            _forbid_dyndns(existing_record)
            if not isinstance(existing_record, ARecord):
                # Exclude aliases etc.
                raise ArgumentError(
                    "{0} cannot be used for address assignment.".format(
                        existing_record))

            # Verify that the existing record is in the network environment the
            # caller expects
            _check_netenv_compat(existing_record, network_environment)

            ip = existing_record.ip
            dbnetwork = existing_record.network

            dbnetwork.lock_row()

    if existing_record.hardware_entity:
        raise ArgumentError(
            "{0} is already used as the primary name of {1:cl} "
            "{1.label}.".format(existing_record,
                                existing_record.hardware_entity))

    if preclude and not newly_created:
        raise ArgumentError("{0} already exists.".format(existing_record))

    if ip:
        q = session.query(AddressAssignment)
        q = q.filter_by(network=dbnetwork)
        q = q.filter_by(ip=ip)
        addr = q.first()
        if addr:
            raise ArgumentError("IP address {0} is already in use by "
                                "{1:l}.".format(ip, addr.interface))

    return (existing_record, newly_created)
コード例 #38
0
 def render(self, session, dns_environment, **arguments):
     return DnsEnvironment.get_unique(session,
                                      dns_environment,
                                      compel=True,
                                      query_options=[undefer("comments")])
コード例 #39
0
ファイル: search_dns.py プロジェクト: piojo/aquilon
    def render(self, session, fqdn, dns_environment, dns_domain, shortname,
               record_type, ip, network, network_environment, target,
               target_domain, primary_name, used, reverse_override, reverse_ptr,
               fullinfo, style, **kwargs):
        if record_type:
            record_type = record_type.strip().lower()
            if record_type in DNS_RRTYPE_MAP:
                cls = DNS_RRTYPE_MAP[record_type]
            else:
                cls = DnsRecord.polymorphic_subclass(record_type,
                                                     "Unknown DNS record type")
            q = session.query(cls)
        else:
            q = session.query(DnsRecord)
            q = q.with_polymorphic('*')

        dbnet_env = NetworkEnvironment.get_unique_or_default(session,
                                                             network_environment)
        if network_environment:
            # The network environment determines the DNS environment
            dbdns_env = dbnet_env.dns_environment
        else:
            dbdns_env = DnsEnvironment.get_unique_or_default(session,
                                                             dns_environment)

        if fqdn:
            dbfqdn = Fqdn.get_unique(session, fqdn=fqdn,
                                     dns_environment=dbdns_env, compel=True)
            q = q.filter_by(fqdn=dbfqdn)

        q = q.join((Fqdn, DnsRecord.fqdn_id == Fqdn.id))
        q = q.filter_by(dns_environment=dbdns_env)
        q = q.options(contains_eager('fqdn'))

        if dns_domain:
            dbdns_domain = DnsDomain.get_unique(session, dns_domain,
                                                compel=True)
            q = q.filter_by(dns_domain=dbdns_domain)
        if shortname:
            q = q.filter_by(name=shortname)

        q = q.join(DnsDomain)
        q = q.options(contains_eager('fqdn.dns_domain'))
        q = q.order_by(Fqdn.name, DnsDomain.name)

        q = q.reset_joinpoint()

        if ip:
            q = q.join(Network)
            q = q.filter_by(network_environment=dbnet_env)
            q = q.reset_joinpoint()
            q = q.filter(ARecord.ip == ip)
        if network:
            dbnetwork = Network.get_unique(session, network,
                                           network_environment=dbnet_env, compel=True)
            q = q.filter(ARecord.network == dbnetwork)
        if target:
            dbtarget = Fqdn.get_unique(session, fqdn=target,
                                       dns_environment=dbdns_env, compel=True)
            q = q.filter(or_(Alias.target == dbtarget,
                             SrvRecord.target == dbtarget))
        if target_domain:
            dbdns_domain = DnsDomain.get_unique(session, target_domain,
                                                compel=True)
            TargetFqdn = aliased(Fqdn)
            q = q.join((TargetFqdn, or_(Alias.target_id == TargetFqdn.id,
                                        SrvRecord.target_id == TargetFqdn.id)))
            q = q.filter(TargetFqdn.dns_domain == dbdns_domain)
        if primary_name is not None:
            if primary_name:
                q = q.filter(DnsRecord.hardware_entity.has())
            else:
                q = q.filter(~DnsRecord.hardware_entity.has())
        if used is not None:
            if used:
                q = q.join(AddressAssignment,
                           and_(ARecord.network_id == AddressAssignment.network_id,
                                ARecord.ip == AddressAssignment.ip))
            else:
                q = q.outerjoin(AddressAssignment,
                                and_(ARecord.network_id == AddressAssignment.network_id,
                                     ARecord.ip == AddressAssignment.ip))
                q = q.filter(AddressAssignment.id == None)
            q = q.reset_joinpoint()
        if reverse_override is not None:
            if reverse_override:
                q = q.filter(ARecord.reverse_ptr.has())
            else:
                q = q.filter(~ARecord.reverse_ptr.has())
        if reverse_ptr:
            dbtarget = Fqdn.get_unique(session, fqdn=reverse_ptr,
                                       dns_environment=dbdns_env, compel=True)
            q = q.filter(ARecord.reverse_ptr == dbtarget)

        if fullinfo or style != "raw":
            q = q.options(undefer('comments'),
                          subqueryload('hardware_entity'),
                          lazyload('hardware_entity.primary_name'),
                          undefer('alias_cnt'))
            return q.all()
        else:
            return StringAttributeList(q.all(), 'fqdn')
コード例 #40
0
    def render(self, session, logger, fqdn, ip, dns_environment, network_environment, **arguments):

        if network_environment:
            if not isinstance(network_environment, NetworkEnvironment):
                network_environment = NetworkEnvironment.get_unique_or_default(session,
                                                                               network_environment)
            if not dns_environment:
                dns_environment = network_environment.dns_environment

        dbdns_env = DnsEnvironment.get_unique(session, dns_environment,
                                              compel=True)

        with DeleteKey("system", logger=logger):
            # We can't use get_unique() here, since we always want to filter by
            # DNS environment, even if no FQDN was given
            q = session.query(ARecord)
            if ip:
                q = q.filter_by(ip=ip)
            q = q.join(ARecord.fqdn)
            q = q.options(contains_eager('fqdn'))
            q = q.filter_by(dns_environment=dbdns_env)
            if fqdn:
                (name, dbdns_domain) = parse_fqdn(session, fqdn)
                q = q.filter_by(name=name)
                q = q.filter_by(dns_domain=dbdns_domain)
            try:
                dbaddress = q.one()
            except NoResultFound:
                parts = []
                if fqdn:
                    parts.append(fqdn)
                if ip:
                    parts.append("ip %s" % ip)
                raise NotFoundException("DNS Record %s not found." %
                                        ", ".join(parts))
            except MultipleResultsFound:
                parts = []
                if fqdn:
                    parts.append(fqdn)
                if ip:
                    parts.append("ip %s" % ip)
                raise NotFoundException("DNS Record %s is not unique." %
                                        ", ".join(parts))

            if dbaddress.hardware_entity:
                raise ArgumentError("DNS Record {0:a} is the primary name of "
                                    "{1:l}, therefore it cannot be "
                                    "deleted.".format(dbaddress,
                                                      dbaddress.hardware_entity))

            if dbaddress.service_address:
                # TODO: print the holder object
                raise ArgumentError("DNS Record {0:a} is used as a service "
                                    "address, therefore it cannot be deleted."
                                    .format(dbaddress))

            # Do not allow deleting the DNS record if the IP address is still in
            # use - except if there are other DNS records having the same
            # address
            if dbaddress.assignments:
                last_use = []
                # FIXME: race condition here, we should use
                # SELECT ... FOR UPDATE
                for addr in dbaddress.assignments:
                    if len(addr.dns_records) == 1:
                        last_use.append(addr)
                if last_use:
                    users = " ,".join([format(addr.interface, "l") for addr in
                                       last_use])
                    raise ArgumentError("IP address %s is still in use by %s." %
                                        (ip, users))
            ip = dbaddress.ip
            old_fqdn = str(dbaddress.fqdn)
            old_comments = dbaddress.comments
            delete_dns_record(dbaddress)
            session.flush()

            if dbdns_env.is_default:
                dsdb_runner = DSDBRunner(logger=logger)
                dsdb_runner.delete_host_details(old_fqdn, ip,
                                                comments=old_comments)
                dsdb_runner.commit_or_rollback()

        return
コード例 #41
0
ファイル: search_dns.py プロジェクト: ned21/aquilon
    def render(self, session, fqdn, dns_environment, dns_domain, shortname,
               record_type, ip, network, network_environment, target,
               target_domain, primary_name, used, reverse_override,
               reverse_ptr, fullinfo, style, **kwargs):
        if record_type:
            record_type = record_type.strip().lower()
            if record_type in DNS_RRTYPE_MAP:
                cls = DNS_RRTYPE_MAP[record_type]
            else:
                cls = DnsRecord.polymorphic_subclass(
                    record_type, "Unknown DNS record type")
            q = session.query(cls)
        else:
            q = session.query(DnsRecord)
            q = q.with_polymorphic('*')

        dbnet_env = NetworkEnvironment.get_unique_or_default(
            session, network_environment)
        if network_environment:
            # The network environment determines the DNS environment
            dbdns_env = dbnet_env.dns_environment
        else:
            dbdns_env = DnsEnvironment.get_unique_or_default(
                session, dns_environment)

        if fqdn:
            dbfqdn = Fqdn.get_unique(session,
                                     fqdn=fqdn,
                                     dns_environment=dbdns_env,
                                     compel=True)
            q = q.filter_by(fqdn=dbfqdn)

        q = q.join((Fqdn, DnsRecord.fqdn_id == Fqdn.id))
        q = q.filter_by(dns_environment=dbdns_env)
        q = q.options(contains_eager('fqdn'))

        if dns_domain:
            dbdns_domain = DnsDomain.get_unique(session,
                                                dns_domain,
                                                compel=True)
            q = q.filter_by(dns_domain=dbdns_domain)
        if shortname:
            q = q.filter_by(name=shortname)

        q = q.join(DnsDomain)
        q = q.options(contains_eager('fqdn.dns_domain'))
        q = q.order_by(Fqdn.name, DnsDomain.name)

        q = q.reset_joinpoint()

        if ip:
            q = q.join(Network)
            q = q.filter_by(network_environment=dbnet_env)
            q = q.reset_joinpoint()
            q = q.filter(ARecord.ip == ip)
        if network:
            dbnetwork = Network.get_unique(session,
                                           network,
                                           network_environment=dbnet_env,
                                           compel=True)
            q = q.filter(ARecord.network == dbnetwork)
        if target:
            dbtarget = Fqdn.get_unique(session,
                                       fqdn=target,
                                       dns_environment=dbdns_env,
                                       compel=True)
            q = q.filter(
                or_(Alias.target == dbtarget, SrvRecord.target == dbtarget))
        if target_domain:
            dbdns_domain = DnsDomain.get_unique(session,
                                                target_domain,
                                                compel=True)
            TargetFqdn = aliased(Fqdn)
            q = q.join((TargetFqdn,
                        or_(Alias.target_id == TargetFqdn.id,
                            SrvRecord.target_id == TargetFqdn.id)))
            q = q.filter(TargetFqdn.dns_domain == dbdns_domain)
        if primary_name is not None:
            if primary_name:
                q = q.filter(DnsRecord.hardware_entity.has())
            else:
                q = q.filter(~DnsRecord.hardware_entity.has())
        if used is not None:
            if used:
                q = q.join(
                    AddressAssignment,
                    and_(ARecord.network_id == AddressAssignment.network_id,
                         ARecord.ip == AddressAssignment.ip))
            else:
                q = q.outerjoin(
                    AddressAssignment,
                    and_(ARecord.network_id == AddressAssignment.network_id,
                         ARecord.ip == AddressAssignment.ip))
                q = q.filter(AddressAssignment.id == None)
            q = q.reset_joinpoint()
        if reverse_override is not None:
            if reverse_override:
                q = q.filter(ARecord.reverse_ptr.has())
            else:
                q = q.filter(~ARecord.reverse_ptr.has())
        if reverse_ptr:
            dbtarget = Fqdn.get_unique(session,
                                       fqdn=reverse_ptr,
                                       dns_environment=dbdns_env,
                                       compel=True)
            q = q.filter(ARecord.reverse_ptr == dbtarget)

        if fullinfo:
            q = q.options(undefer('comments'))
            q = q.options(subqueryload('hardware_entity'))
            q = q.options(undefer('alias_cnt'))
            return q.all()
        elif style == "raw":
            return StringAttributeList(q.all(), 'fqdn')
        else:
            # This is for the CSV formatter
            return q.all()
コード例 #42
0
ファイル: dns.py プロジェクト: jrha/aquilon
def grab_address(session, fqdn, ip, network_environment=None,
                 dns_environment=None, comments=None,
                 allow_restricted_domain=False, allow_multi=False,
                 allow_reserved=False, relaxed=False, preclude=False):
    """
    Take ownership of an address.

    This is a bit complicated because due to DNS propagation delays, we want to
    allow users to pre-define a DNS address and then assign the address to a
    host later.

    Parameters:
        session: SQLA session handle
        fqdn: the name to allocate/take over
        ip: the IP address to allocate/take over
        network_environment: where the IP address lives
        dns_enviromnent: where the FQDN lives
        comments: any comments to attach to the DNS record if it is created as new
        allow_restricted_domain: if True, adding entries to restricted DNS
            domains is allowed, otherwise it is denied. Default is False.
        allow_multi: if True, allow the same FQDN to be added multiple times with
            different IP addresses. Deault is False.
        allow_reserved: if True, allow creating a ReservedName instead of an
            ARecord if no IP address was specified. Default is False.
        preclude: if True, forbid taking over an existing DNS record, even if it
            is not referenced by any AddressAssignment records. Default is
            False.
    """
    if not isinstance(network_environment, NetworkEnvironment):
        network_environment = NetworkEnvironment.get_unique_or_default(session,
                                                                       network_environment)
    if not dns_environment:
        dns_environment = network_environment.dns_environment
    elif not isinstance(dns_environment, DnsEnvironment):
        dns_environment = DnsEnvironment.get_unique(session, dns_environment,
                                                    compel=True)

    # Non-default DNS environments may contain anything, but we want to keep
    # the internal environment clean
    if dns_environment.is_default and not network_environment.is_default:
        raise ArgumentError("Entering external IP addresses to the "
                            "internal DNS environment is not allowed.")

    short, dbdns_domain = parse_fqdn(session, fqdn)

    # Lock the domain to prevent adding/deleting records while we're checking
    # FQDN etc. availability
    dbdns_domain.lock_row()

    if dbdns_domain.restricted and not allow_restricted_domain:
        raise ArgumentError("{0} is restricted, adding extra addresses "
                            "is not allowed.".format(dbdns_domain))

    dbfqdn = Fqdn.get_or_create(session, dns_environment=dns_environment,
                                name=short, dns_domain=dbdns_domain,
                                query_options=[joinedload('dns_records')])

    existing_record = None
    newly_created = False

    if ip:
        dbnetwork = get_net_id_from_ip(session, ip, network_environment)
        check_ip_restrictions(dbnetwork, ip, relaxed=relaxed)

        dbnetwork.lock_row()

        # No filtering on DNS environment. If an address is dynamic in one
        # environment, it should not be considered static in a different
        # environment.
        q = session.query(DynamicStub)
        q = q.filter_by(network=dbnetwork)
        q = q.filter_by(ip=ip)
        dbdns_rec = q.first()
        _forbid_dyndns(dbdns_rec)

        # Verify that no other record uses the same IP address, this time taking
        # the DNS environemt into consideration.
        # While the DNS would allow different A records to point to the same IP
        # address, the current user expectation is that creating a DNS entry
        # also counts as a reservation, so we can not allow this use case. If we
        # want to implement such a feature later, the best way would be to
        # subclass Alias and let that subclass emit an A record instead of a
        # CNAME when the dump_dns command is called.
        q = session.query(ARecord)
        q = q.filter_by(network=dbnetwork)
        q = q.filter_by(ip=ip)
        q = q.join(ARecord.fqdn)
        q = q.filter_by(dns_environment=dns_environment)
        dbrecords = q.all()
        if dbrecords and len(dbrecords) > 1:  # pragma: no cover
            # We're just trying to make sure this never happens
            raise AquilonError("IP address %s is referenced by multiple "
                               "DNS records: %s" %
                               (ip, ", ".join([format(rec, "a")
                                               for rec in dbrecords])))
        if dbrecords and dbrecords[0].fqdn != dbfqdn:
            raise ArgumentError("IP address {0} is already in use by {1:l}."
                                .format(ip, dbrecords[0]))

        # Check if the name is used already
        for dbdns_rec in dbfqdn.dns_records:
            if isinstance(dbdns_rec, ARecord):
                _forbid_dyndns(dbdns_rec)
                _check_netenv_compat(dbdns_rec, network_environment)
                if dbdns_rec.ip == ip and dbdns_rec.network == dbnetwork:
                    existing_record = dbdns_rec
                elif not allow_multi:
                    raise ArgumentError("{0} points to a different IP address."
                                        .format(dbdns_rec))

            elif isinstance(dbdns_rec, ReservedName):
                existing_record = convert_reserved_to_arecord(session,
                                                              dbdns_rec,
                                                              dbnetwork, ip)
                newly_created = True
            else:
                # Exclude aliases etc.
                raise ArgumentError("{0} cannot be used for address assignment."
                                    .format(dbdns_rec))

        if not existing_record:
            existing_record = ARecord(fqdn=dbfqdn, ip=ip, network=dbnetwork,
                                      comments=comments)
            session.add(existing_record)
            newly_created = True
    else:
        if not dbfqdn.dns_records:
            # There's no IP, and the name did not exist before. Create a
            # reservation, but only if the caller allowed that use case.
            if not allow_reserved:
                raise ArgumentError("DNS Record %s does not exist." % dbfqdn)

            existing_record = ReservedName(fqdn=dbfqdn, comments=comments)
            newly_created = True
        else:
            # There's no IP, but the name is already in use. We need a single IP
            # address.
            if len(dbfqdn.dns_records) > 1:
                raise ArgumentError("{0} does not resolve to a single IP address."
                                    .format(dbfqdn))

            existing_record = dbfqdn.dns_records[0]
            _forbid_dyndns(existing_record)
            if not isinstance(existing_record, ARecord):
                # Exclude aliases etc.
                raise ArgumentError("{0} cannot be used for address assignment."
                                    .format(existing_record))

            # Verify that the existing record is in the network environment the
            # caller expects
            _check_netenv_compat(existing_record, network_environment)

            ip = existing_record.ip
            dbnetwork = existing_record.network

            dbnetwork.lock_row()

    if existing_record.hardware_entity:
        raise ArgumentError("{0} is already used as the primary name of {1:cl} "
                            "{1.label}.".format(existing_record,
                                                existing_record.hardware_entity))

    if preclude and not newly_created:
        raise ArgumentError("{0} already exists.".format(existing_record))

    if ip:
        q = session.query(AddressAssignment)
        q = q.filter_by(network=dbnetwork)
        q = q.filter_by(ip=ip)
        addr = q.first()
        if addr:
            raise ArgumentError("IP address {0} is already in use by "
                                "{1:l}.".format(ip, addr.interface))

    return (existing_record, newly_created)
コード例 #43
0
ファイル: add_dynamic_range.py プロジェクト: ned21/aquilon
    def render(self, session, logger, startip, endip, dns_domain, prefix,
               **arguments):
        if not prefix:
            prefix = 'dynamic'
        dbnet_env = NetworkEnvironment.get_unique_or_default(session)
        dbdns_env = DnsEnvironment.get_unique_or_default(session)
        startnet = get_net_id_from_ip(session, startip, dbnet_env)
        endnet = get_net_id_from_ip(session, endip, dbnet_env)
        if startnet != endnet:
            raise ArgumentError("IP addresses %s (%s) and %s (%s) must be on "
                                "the same subnet." %
                                (startip, startnet.ip, endip, endnet.ip))
        dbdns_domain = DnsDomain.get_unique(session, dns_domain, compel=True)

        dbdns_domain.lock_row()
        startnet.lock_row()

        q = session.query(AddressAssignment.ip)
        q = q.filter_by(network=startnet)
        q = q.filter(AddressAssignment.ip >= startip)
        q = q.filter(AddressAssignment.ip <= endip)
        q = q.order_by(AddressAssignment.ip)
        conflicts = q.all()
        if conflicts:
            raise ArgumentError(
                "Cannot allocate the address range because the "
                "following IP addresses are already in use:\n" +
                ", ".join([str(c.ip) for c in conflicts]))

        # No filtering on DNS environment. If an address is dynamic in one
        # environment, it should not be considered static in a different
        # environment.
        q = session.query(ARecord)
        q = q.filter_by(network=startnet)
        q = q.filter(ARecord.ip >= startip)
        q = q.filter(ARecord.ip <= endip)
        q = q.order_by(ARecord.ip)
        conflicts = q.all()
        if conflicts:
            raise ArgumentError(
                "Cannot allocate the address range because the "
                "following DNS records already exist:\n" +
                "\n".join([format(c, "a") for c in conflicts]))

        dsdb_runner = DSDBRunner(logger=logger)
        with session.no_autoflush:
            for ipint in range(int(startip), int(endip) + 1):
                ip = IPv4Address(ipint)
                check_ip_restrictions(startnet, ip)
                name = "%s-%s" % (prefix, str(ip).replace('.', '-'))
                dbfqdn = Fqdn.get_or_create(session,
                                            name=name,
                                            dns_domain=dbdns_domain,
                                            dns_environment=dbdns_env,
                                            preclude=True)
                dbdynamic_stub = DynamicStub(fqdn=dbfqdn,
                                             ip=ip,
                                             network=startnet)
                session.add(dbdynamic_stub)
                dsdb_runner.add_host_details(dbfqdn, ip)

        session.flush()
        # This may take some time if the range is big, so be verbose
        dsdb_runner.commit_or_rollback("Could not add addresses to DSDB",
                                       verbose=True)

        return
コード例 #44
0
ファイル: add_dynamic_range.py プロジェクト: jrha/aquilon
    def render(self, session, logger, startip, endip, dns_domain, prefix,
               **arguments):
        if not prefix:
            prefix = 'dynamic'
        dbnet_env = NetworkEnvironment.get_unique_or_default(session)
        dbdns_env = DnsEnvironment.get_unique_or_default(session)
        startnet = get_net_id_from_ip(session, startip, dbnet_env)
        endnet = get_net_id_from_ip(session, endip, dbnet_env)
        if startnet != endnet:
            raise ArgumentError("IP addresses %s (%s) and %s (%s) must be on "
                                "the same subnet." %
                                (startip, startnet.ip, endip, endnet.ip))
        dbdns_domain = DnsDomain.get_unique(session, dns_domain, compel=True)

        dbdns_domain.lock_row()
        startnet.lock_row()

        q = session.query(AddressAssignment.ip)
        q = q.filter_by(network=startnet)
        q = q.filter(AddressAssignment.ip >= startip)
        q = q.filter(AddressAssignment.ip <= endip)
        q = q.order_by(AddressAssignment.ip)
        conflicts = q.all()
        if conflicts:
            raise ArgumentError("Cannot allocate the address range because the "
                                "following IP addresses are already in use:\n" +
                                ", ".join([str(c.ip) for c in conflicts]))

        # No filtering on DNS environment. If an address is dynamic in one
        # environment, it should not be considered static in a different
        # environment.
        q = session.query(ARecord)
        q = q.filter_by(network=startnet)
        q = q.filter(ARecord.ip >= startip)
        q = q.filter(ARecord.ip <= endip)
        q = q.order_by(ARecord.ip)
        conflicts = q.all()
        if conflicts:
            raise ArgumentError("Cannot allocate the address range because the "
                                "following DNS records already exist:\n" +
                                "\n".join([format(c, "a") for c in conflicts]))

        dsdb_runner = DSDBRunner(logger=logger)
        with session.no_autoflush:
            for ipint in range(int(startip), int(endip) + 1):
                ip = IPv4Address(ipint)
                check_ip_restrictions(startnet, ip)
                name = "%s-%s" % (prefix, str(ip).replace('.', '-'))
                dbfqdn = Fqdn.get_or_create(session, name=name,
                                            dns_domain=dbdns_domain,
                                            dns_environment=dbdns_env,
                                            preclude=True)
                dbdynamic_stub = DynamicStub(fqdn=dbfqdn, ip=ip, network=startnet)
                session.add(dbdynamic_stub)
                dsdb_runner.add_host_details(dbfqdn, ip)

        session.flush()
        # This may take some time if the range is big, so be verbose
        dsdb_runner.commit_or_rollback("Could not add addresses to DSDB",
                                       verbose=True)

        return
コード例 #45
0
 def render(self, session, dns_environment, **arguments):
     return DnsEnvironment.get_unique(session, dns_environment, compel=True, query_options=[undefer("comments")])
コード例 #46
0
def setup():
    dmn = DnsDomain.get_unique(sess, DNS_DOMAIN_NAME, compel=True)
    assert isinstance(dmn, DnsDomain), 'No ms.com domain in %s' % func_name()

    intrnl = DnsEnvironment.get_unique(sess, DNS_ENV, compel=True)
    assert isinstance(dmn, DnsDomain), 'No internal env in %s' % func_name()