Пример #1
0
    def render(self, session, logger, auxiliary, **arguments):
        # Check dependencies, translate into user-friendly message
        dbauxiliary = ARecord.get_unique(session, fqdn=auxiliary, compel=True)

        is_aux = True
        if not dbauxiliary.assignments or len(dbauxiliary.assignments) > 1:
            is_aux = False
        else:
            assignment = dbauxiliary.assignments[0]
            dbinterface = assignment.interface

            if assignment.ip == dbinterface.hardware_entity.primary_ip:
                is_aux = False
            if assignment.interface.interface_type == 'management':
                is_aux = False

        if not is_aux:
            raise ArgumentError("{0:a} is not an auxiliary.".format(dbauxiliary))

        return super(CommandDelAuxiliary, self).render(session, logger,
                                                       machine=dbinterface.hardware_entity.label,
                                                       chassis=None, network_device=None,
                                                       interface=dbinterface.name,
                                                       fqdn=auxiliary,
                                                       ip=assignment.ip,
                                                       label=None,
                                                       keep_dns=False,
                                                       network_environment=None,
                                                       **arguments)
Пример #2
0
    def render(self, session, dbuser,
               ip, fqdn, network_environment, **arguments):
        dbnet_env = NetworkEnvironment.get_unique_or_default(session,
                                                             network_environment)
        self.az.check_network_environment(dbuser, dbnet_env)
        if fqdn:
            dbdns_rec = ARecord.get_unique(session, fqdn=fqdn,
                                           dns_environment=dbnet_env.dns_environment,
                                           compel=True)
            ip = dbdns_rec.ip
        elif not ip:
            raise ArgumentError("Please specify either --ip or --fqdn.")

        dbnetwork = get_net_id_from_ip(session, ip, dbnet_env)
        dbrouter = None
        for rtaddr in dbnetwork.routers:
            if rtaddr.ip == ip:
                dbrouter = rtaddr
                break
        if not dbrouter:
            raise NotFoundException("IP address {0} is not a router on "
                                    "{1:l}.".format(ip, dbnetwork))

        map(delete_dns_record, dbrouter.dns_records)
        dbnetwork.routers.remove(dbrouter)
        session.flush()

        # TODO: update the templates of Zebra hosts on the network

        return
Пример #3
0
    def render(self, session, dbuser,
               ip, fqdn, network_environment, **arguments):
        dbnet_env = NetworkEnvironment.get_unique_or_default(session,
                                                             network_environment)
        self.az.check_network_environment(dbuser, dbnet_env)
        if fqdn:
            dbdns_rec = ARecord.get_unique(session, fqdn=fqdn,
                                           dns_environment=dbnet_env.dns_environment,
                                           compel=True)
            ip = dbdns_rec.ip
        elif not ip:
            raise ArgumentError("Please specify either --ip or --fqdn.")

        dbnetwork = get_net_id_from_ip(session, ip, dbnet_env)
        dbrouter = None
        for rtaddr in dbnetwork.routers:
            if rtaddr.ip == ip:
                dbrouter = rtaddr
                break
        if not dbrouter:
            raise NotFoundException("IP address {0} is not a router on "
                                    "{1:l}.".format(ip, dbnetwork))

        map(delete_dns_record, dbrouter.dns_records)
        dbnetwork.routers.remove(dbrouter)
        session.flush()

        # TODO: update the templates of Zebra hosts on the network

        return
Пример #4
0
    def render(self, session, ip, fqdn, all, network_environment, **arguments):
        dbnet_env = NetworkEnvironment.get_unique_or_default(session,
                                                             network_environment)

        q = session.query(RouterAddress)

        q = q.join(Network)
        q = q.filter_by(network_environment=dbnet_env)
        q = q.options(contains_eager('network'))
        q = q.reset_joinpoint()

        q = q.options(undefer(RouterAddress.comments))
        q = q.options(joinedload('location'))
        q = q.options(joinedload('dns_records'))

        if all:
            return q.all()

        if fqdn:
            dbdns_rec = ARecord.get_unique(session, fqdn=fqdn, compel=True)
            ip = dbdns_rec.ip
            errmsg = "named %s" % fqdn
        elif ip:
            errmsg = "with IP address %s" % ip
        else:
            raise ArgumentError("Please specify either --ip or --fqdn.")

        q = q.filter(RouterAddress.ip == ip)

        try:
            return q.one()
        except NoResultFound:
            raise NotFoundException("Router %s not found." % errmsg)
Пример #5
0
    def render(self, session, ip, fqdn, all, network_environment, **arguments):
        dbnet_env = NetworkEnvironment.get_unique_or_default(
            session, network_environment)

        q = session.query(RouterAddress)

        q = q.join(Network)
        q = q.filter_by(network_environment=dbnet_env)
        q = q.options(contains_eager('network'))
        q = q.reset_joinpoint()

        q = q.options(undefer(RouterAddress.comments))
        q = q.options(joinedload('location'))
        q = q.options(joinedload('dns_records'))

        if all:
            return q.all()

        if fqdn:
            dbdns_rec = ARecord.get_unique(session, fqdn=fqdn, compel=True)
            ip = dbdns_rec.ip
            errmsg = "named %s" % fqdn
        elif ip:
            errmsg = "with IP address %s" % ip
        else:
            raise ArgumentError("Please specify either --ip or --fqdn.")

        q = q.filter(RouterAddress.ip == ip)

        try:
            return q.one()
        except NoResultFound:
            raise NotFoundException("Router %s not found." % errmsg)
Пример #6
0
    def render(self, session, fqdn, dns_domain, **arguments):
        dbdns_domain = DnsDomain.get_unique(session, dns_domain, compel=True)

        dba_rec = ARecord.get_unique(session, fqdn=fqdn, compel=True)

        ns_record = NsRecord.get_unique(session, dns_domain=dbdns_domain,
                                        a_record=dba_rec, compel=True)

        session.delete(ns_record)
        return
Пример #7
0
    def render(self, session, fqdn, dns_domain, **arguments):
        dbdns_domain = DnsDomain.get_unique(session, dns_domain, compel=True)

        dba_rec = ARecord.get_unique(session, fqdn=fqdn, compel=True)

        ns_record = NsRecord.get_unique(session,
                                        dns_domain=dbdns_domain,
                                        a_record=dba_rec,
                                        compel=True)

        session.delete(ns_record)
        return
Пример #8
0
    def render(self, session, dbuser, fqdn, building, ip, network_environment,
               comments, **arguments):
        dbnet_env = NetworkEnvironment.get_unique_or_default(
            session, network_environment)
        self.az.check_network_environment(dbuser, dbnet_env)

        if building:
            dbbuilding = Building.get_unique(session, building, compel=True)
        else:
            dbbuilding = None

        (short, dbdns_domain) = parse_fqdn(session, fqdn)
        dbfqdn = Fqdn.get_or_create(session,
                                    name=short,
                                    dns_domain=dbdns_domain,
                                    dns_environment=dbnet_env.dns_environment)
        if ip:
            dbnetwork = get_net_id_from_ip(session, ip, dbnet_env)
            dbdns_rec = ARecord.get_or_create(session,
                                              fqdn=dbfqdn,
                                              ip=ip,
                                              network=dbnetwork)
        else:
            dbdns_rec = ARecord.get_unique(session, dbfqdn, compel=True)
            ip = dbdns_rec.ip
            dbnetwork = dbdns_rec.network

        assert ip in dbnetwork.network, "IP %s is outside network %s" % (
            ip, dbnetwork.ip)

        if ip in dbnetwork.router_ips:
            raise ArgumentError(
                "IP address {0} is already present as a router "
                "for {1:l}.".format(ip, dbnetwork))

        # Policy checks are valid only for internal networks
        if dbnetwork.is_internal:
            if ip >= dbnetwork.first_usable_host or \
               int(ip) - int(dbnetwork.ip) in dbnetwork.reserved_offsets:
                raise ArgumentError(
                    "IP address {0} is not a valid router address "
                    "on {1:l}.".format(ip, dbnetwork))

        dbnetwork.routers.append(
            RouterAddress(ip=ip,
                          location=dbbuilding,
                          dns_environment=dbdns_rec.fqdn.dns_environment,
                          comments=comments))
        session.flush()

        # TODO: update the templates of Zebra hosts on the network

        return
Пример #9
0
    def render(self, session, dns_domain, **kw):
        dbdns = DnsDomain.get_unique(session, dns_domain, compel=True)
        q = session.query(NsRecord).filter_by(dns_domain=dbdns)

        dba_record = ARecord.get_unique(session, fqdn=kw['fqdn'], compel=True)
        q = q.filter_by(a_record=dba_record)
        ns_rec = q.all()

        if not ns_rec:
            raise NotFoundException(
                "Could not find a dns_record for domain '%s'." % dns_domain)

        return ns_rec
Пример #10
0
    def render(self, session, dns_domain, **kw):
        dbdns = DnsDomain.get_unique(session, dns_domain, compel=True)
        q = session.query(NsRecord).filter_by(dns_domain=dbdns)

        dba_record = ARecord.get_unique(session, fqdn=kw['fqdn'], compel=True)
        q = q.filter_by(a_record=dba_record)
        ns_rec = q.all()

        if not ns_rec:
            raise NotFoundException(
                "Could not find a dns_record for domain '%s'." % dns_domain)

        return ns_rec
Пример #11
0
    def render(self, session, auxiliary, **kwargs):
        dbdns_rec = ARecord.get_unique(session, fqdn=auxiliary, compel=True)
        if not dbdns_rec.assignments:
            raise ArgumentError("Address {0:a} is not assigned to any "
                                "interfaces.".format(dbdns_rec))
        hws = []
        for addr in dbdns_rec.assignments:
            iface = addr.interface
            if iface.interface_type != 'public':
                raise ArgumentError("{0:a} is not an auxiliary.".format(dbdns_rec))
            hws.append(iface.hardware_entity)

        return hws
Пример #12
0
    def render(self, session, logger, auxiliary, **arguments):
        dbmachine = None
        with DeleteKey("system", logger=logger):
            # Check dependencies, translate into user-friendly message
            dbauxiliary = ARecord.get_unique(session,
                                             fqdn=auxiliary,
                                             compel=True)
            is_aux = True
            if not dbauxiliary.assignments or len(dbauxiliary.assignments) > 1:
                is_aux = False
            else:
                assignment = dbauxiliary.assignments[0]
                dbmachine = assignment.interface.hardware_entity

                if assignment.ip == dbmachine.primary_ip:
                    is_aux = False
                if assignment.interface.interface_type == 'management':
                    is_aux = False

            if not is_aux:
                raise ArgumentError(
                    "{0:a} is not an auxiliary.".format(dbauxiliary))

            # FIXME: Look for dependencies...

            oldinfo = DSDBRunner.snapshot_hw(dbmachine)

            session.delete(assignment)
            delete_dns_record(dbauxiliary)
            session.flush()
            session.expire(dbmachine)

            dsdb_runner = DSDBRunner(logger=logger)
            dsdb_runner.update_host(dbmachine, oldinfo)
            dsdb_runner.commit_or_rollback(
                "Could not remove host %s from DSDB" % auxiliary)
            # Past the point of no return here (DSDB has been updated)...
            # probably not much of an issue if writing the plenary failed.
            # Commit the session so that we can free the delete lock.
            session.commit()

        if dbmachine:
            plenary_info = PlenaryMachineInfo(dbmachine, logger=logger)
            # This may create a new lock, so we free first above.
            plenary_info.write()

            if dbmachine.host:
                # FIXME: Reconfigure
                pass

        return
Пример #13
0
    def render(self, session, auxiliary, **kwargs):
        dbdns_rec = ARecord.get_unique(session, fqdn=auxiliary, compel=True)
        if not dbdns_rec.assignments:
            raise ArgumentError("Address {0:a} is not assigned to any "
                                "interfaces.".format(dbdns_rec))
        hws = []
        for addr in dbdns_rec.assignments:
            iface = addr.interface
            if iface.interface_type != 'public':
                raise ArgumentError(
                    "{0:a} is not an auxiliary.".format(dbdns_rec))
            hws.append(iface.hardware_entity)

        return hws
Пример #14
0
    def render(self, session, fqdn, dns_domain, comments, **arguments):

        dbdns_domain = DnsDomain.get_unique(session, dns_domain, compel=True)
        dba_rec = ARecord.get_unique(session, fqdn=fqdn, compel=True)

        NsRecord.get_unique(session, a_record=dba_rec, dns_domain=dbdns_domain,
                            preclude=True)

        ns_record = NsRecord(a_record=dba_rec, dns_domain=dbdns_domain,
                             comments=comments)

        session.add(ns_record)

        return
Пример #15
0
    def render(self, session, logger, auxiliary, **arguments):
        dbmachine = None
        with DeleteKey("system", logger=logger):
            # Check dependencies, translate into user-friendly message
            dbauxiliary = ARecord.get_unique(session, fqdn=auxiliary, compel=True)
            is_aux = True
            if not dbauxiliary.assignments or len(dbauxiliary.assignments) > 1:
                is_aux = False
            else:
                assignment = dbauxiliary.assignments[0]
                dbmachine = assignment.interface.hardware_entity

                if assignment.ip == dbmachine.primary_ip:
                    is_aux = False
                if assignment.interface.interface_type == "management":
                    is_aux = False

            if not is_aux:
                raise ArgumentError("{0:a} is not an auxiliary.".format(dbauxiliary))

            # FIXME: Look for dependencies...

            oldinfo = DSDBRunner.snapshot_hw(dbmachine)

            session.delete(assignment)
            delete_dns_record(dbauxiliary)
            session.flush()
            session.expire(dbmachine)

            dsdb_runner = DSDBRunner(logger=logger)
            dsdb_runner.update_host(dbmachine, oldinfo)
            dsdb_runner.commit_or_rollback("Could not remove host %s from DSDB" % auxiliary)
            # Past the point of no return here (DSDB has been updated)...
            # probably not much of an issue if writing the plenary failed.
            # Commit the session so that we can free the delete lock.
            session.commit()

        if dbmachine:
            plenary_info = PlenaryMachineInfo(dbmachine, logger=logger)
            # This may create a new lock, so we free first above.
            plenary_info.write()

            if dbmachine.host:
                # FIXME: Reconfigure
                pass

        return
Пример #16
0
    def render(self, session, dbuser,
               fqdn, building, ip, network_environment, comments, **arguments):
        dbnet_env = NetworkEnvironment.get_unique_or_default(session,
                                                             network_environment)
        self.az.check_network_environment(dbuser, dbnet_env)

        if building:
            dbbuilding = Building.get_unique(session, building, compel=True)
        else:
            dbbuilding = None

        (short, dbdns_domain) = parse_fqdn(session, fqdn)
        dbfqdn = Fqdn.get_or_create(session, name=short,
                                    dns_domain=dbdns_domain,
                                    dns_environment=dbnet_env.dns_environment)
        if ip:
            dbnetwork = get_net_id_from_ip(session, ip, dbnet_env)
            dbdns_rec = ARecord.get_or_create(session, fqdn=dbfqdn, ip=ip,
                                              network=dbnetwork)
        else:
            dbdns_rec = ARecord.get_unique(session, dbfqdn, compel=True)
            ip = dbdns_rec.ip
            dbnetwork = dbdns_rec.network

        assert ip in dbnetwork.network, "IP %s is outside network %s" % (ip,
                                                                         dbnetwork.ip)

        if ip in dbnetwork.router_ips:
            raise ArgumentError("IP address {0} is already present as a router "
                                "for {1:l}.".format(ip, dbnetwork))

        # Policy checks are valid only for internal networks
        if dbnetwork.is_internal:
            if ip >= dbnetwork.first_usable_host or \
               int(ip) - int(dbnetwork.ip) in dbnetwork.reserved_offsets:
                raise ArgumentError("IP address {0} is not a valid router address "
                                    "on {1:l}.".format(ip, dbnetwork))

        dbnetwork.routers.append(RouterAddress(ip=ip, location=dbbuilding,
                                               dns_environment=dbdns_rec.fqdn.dns_environment,
                                               comments=comments))
        session.flush()

        # TODO: update the templates of Zebra hosts on the network

        return
Пример #17
0
    def render(self, session, fqdn, dns_domain, comments, **arguments):

        dbdns_domain = DnsDomain.get_unique(session, dns_domain, compel=True)
        dba_rec = ARecord.get_unique(session, fqdn=fqdn, compel=True)

        NsRecord.get_unique(session,
                            a_record=dba_rec,
                            dns_domain=dbdns_domain,
                            preclude=True)

        ns_record = NsRecord(a_record=dba_rec,
                             dns_domain=dbdns_domain,
                             comments=comments)

        session.add(ns_record)

        return
Пример #18
0
    def render(self, session, fqdn, ip, building, comments, **arguments):
        if fqdn:
            dbdns_rec = ARecord.get_unique(session, fqdn, compel=True)
            ip = dbdns_rec.ip
        if not ip:
            raise ArgumentError("Please specify either --ip or --fqdn.")

        router = RouterAddress.get_unique(session, ip=ip, compel=True)

        if building:
            dbbuilding = Building.get_unique(session, name=building,
                                             compel=True)
            router.location = dbbuilding

        if comments:
            router.comments = comments

        session.flush()
Пример #19
0
    def render(self, session, fqdn, ip, building, comments, **arguments):
        if fqdn:
            dbdns_rec = ARecord.get_unique(session, fqdn, compel=True)
            ip = dbdns_rec.ip
        if not ip:
            raise ArgumentError("Please specify either --ip or --fqdn.")

        router = RouterAddress.get_unique(session, ip=ip, compel=True)

        if building:
            dbbuilding = Building.get_unique(session,
                                             name=building,
                                             compel=True)
            router.location = dbbuilding

        if comments:
            router.comments = comments

        session.flush()
Пример #20
0
    def render(
        self,
        session,
        logger,
        machine,
        chassis,
        switch,
        interface,
        fqdn,
        ip,
        label,
        keep_dns,
        network_environment,
        **kwargs
    ):

        if machine:
            hwtype = "machine"
            hwname = machine
        elif chassis:
            hwtype = "chassis"
            hwname = chassis
        elif switch:
            hwtype = "switch"
            hwname = switch

        dbhw_ent = HardwareEntity.get_unique(session, hwname, hardware_type=hwtype, compel=True)
        dbinterface = Interface.get_unique(session, hardware_entity=dbhw_ent, name=interface, compel=True)
        dbnet_env = NetworkEnvironment.get_unique_or_default(session, network_environment)

        oldinfo = DSDBRunner.snapshot_hw(dbhw_ent)

        if fqdn:
            dbdns_rec = ARecord.get_unique(session, fqdn=fqdn, dns_environment=dbnet_env.dns_environment, compel=True)
            ip = dbdns_rec.ip

        addr = None
        if ip:
            addr = first_of(dbinterface.assignments, lambda x: x.ip == ip)
            if not addr:
                raise ArgumentError("{0} does not have IP address {1} assigned to " "it.".format(dbinterface, ip))
        elif label is not None:
            addr = first_of(dbinterface.assignments, lambda x: x.label == label)
            if not addr:
                raise ArgumentError("{0} does not have an address with label " "{1}.".format(dbinterface, label))

        if not addr:
            raise ArgumentError("Please specify the address to be removed " "using either --ip, --label, or --fqdn.")

        dbnetwork = addr.network
        ip = addr.ip

        if dbnetwork.network_environment != dbnet_env:
            raise ArgumentError(
                "The specified address lives in {0:l}, not in "
                "{1:l}.  Use the --network_environment option "
                "to select the correct environment.".format(dbnetwork.network_environment, dbnet_env)
            )

        # Forbid removing the primary name
        if ip == dbhw_ent.primary_ip:
            raise ArgumentError("The primary IP address of a hardware entity " "cannot be removed.")

        dbinterface.assignments.remove(addr)

        # Check if the address was assigned to multiple interfaces, and remove
        # the DNS entries if this was the last use
        q = session.query(AddressAssignment)
        q = q.filter_by(network=dbnetwork)
        q = q.filter_by(ip=ip)
        other_uses = q.all()
        if not other_uses and not keep_dns:
            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=dbnet_env.dns_environment)
            map(delete_dns_record, q.all())

        session.flush()

        dbhost = getattr(dbhw_ent, "host", None)
        if dbhost:
            plenary_info = PlenaryHost(dbhost, logger=logger)
            key = plenary_info.get_write_key()
            try:
                lock_queue.acquire(key)
                try:
                    plenary_info.write(locked=True)
                except IncompleteError:
                    # FIXME: if this command is used after "add host" but before
                    # "make", then writing out the template will fail due to
                    # required services not being assigned. Ignore this error
                    # for now.
                    plenary_info.restore_stash()

                dsdb_runner = DSDBRunner(logger=logger)
                dsdb_runner.update_host(dbhw_ent, oldinfo)

                if not other_uses and keep_dns:
                    q = session.query(ARecord)
                    q = q.filter_by(network=dbnetwork)
                    q = q.filter_by(ip=ip)
                    dbdns_rec = q.first()
                    dsdb_runner.add_host_details(dbdns_rec.fqdn, ip)

                dsdb_runner.commit_or_rollback("Could not add host to DSDB")
            except:
                plenary_info.restore_stash()
                raise
            finally:
                lock_queue.release(key)
        else:
            dsdb_runner = DSDBRunner(logger=logger)
            dsdb_runner.update_host(dbhw_ent, oldinfo)
            dsdb_runner.commit_or_rollback("Could not add host to DSDB")

        return
Пример #21
0
def generate_ip(session,
                logger,
                dbinterface,
                ip=None,
                ipfromip=None,
                ipfromsystem=None,
                autoip=None,
                ipalgorithm=None,
                compel=False,
                network_environment=None,
                audit_results=None,
                **kwargs):
    ip_options = [ip, ipfromip, ipfromsystem, autoip]
    numopts = sum([1 if opt else 0 for opt in ip_options])
    if numopts > 1:
        raise ArgumentError("Only one of --ip, --ipfromip, --ipfromsystem "
                            "and --autoip can be specified.")
    elif numopts == 0:
        if compel:
            raise ArgumentError("Please specify one of the --ip, --ipfromip, "
                                "--ipfromsystem, and --autoip parameters.")
        return None

    if ip:
        return ip

    dbsystem = None
    dbnetwork = None
    if autoip:
        if not dbinterface:
            raise ArgumentError("No interface available to automatically "
                                "generate an IP address.")
        if dbinterface.port_group:
            # This could either be an interface from a virtual machine
            # or an interface on an ESX vmhost.
            dbcluster = None
            if getattr(dbinterface.hardware_entity, "cluster", None):
                # VM
                dbcluster = dbinterface.hardware_entity.cluster
            elif getattr(dbinterface.hardware_entity, "host", None):
                dbcluster = dbinterface.hardware_entity.host.cluster
            if not dbcluster:
                raise ArgumentError("Can only automatically assign an IP "
                                    "address to an interface with a port "
                                    "group on virtual machines or ESX hosts.")
            if not dbcluster.switch:
                raise ArgumentError(
                    "Cannot automatically assign an IP "
                    "address to an interface with a port group "
                    "since {0} is not associated with a "
                    "switch.".format(dbcluster))
            vlan_id = VlanInfo.get_vlan_id(session, dbinterface.port_group)
            dbnetwork = ObservedVlan.get_network(session,
                                                 vlan_id=vlan_id,
                                                 switch=dbcluster.switch,
                                                 compel=ArgumentError)
        elif dbinterface.mac:
            q = session.query(ObservedMac)
            q = q.filter_by(mac_address=dbinterface.mac)
            q = q.order_by(desc(ObservedMac.last_seen))
            dbom = q.first()
            if not dbom:
                raise ArgumentError("No switch found in the discovery table "
                                    "for MAC address %s." % dbinterface.mac)
            if not dbom.switch.primary_ip:
                raise ArgumentError("{0} does not have a primary IP address "
                                    "to use for network "
                                    "selection.".format(dbom.switch))
            dbnetwork = get_net_id_from_ip(session, dbom.switch.primary_ip)
        else:
            raise ArgumentError(
                "{0} has neither a MAC address nor port group "
                "information, it is not possible to generate "
                "an IP address automatically.".format(dbinterface))

    if ipfromsystem:
        # Assumes one system entry, not necessarily correct.
        dbdns_rec = ARecord.get_unique(session, fqdn=ipfromsystem, compel=True)
        dbnetwork = dbdns_rec.network

    if ipfromip:
        # determine network
        dbnetwork = get_net_id_from_ip(session, ipfromip, network_environment)

    if not dbnetwork:
        raise ArgumentError("Could not determine network to use for %s." %
                            dbsystem.fqdn)

    # When there are e.g. multiple "add manager --autoip" operations going on in
    # parallel, we must ensure that they won't try to use the same IP address.
    # This query places a database lock on the network, which means IP address
    # generation within a network will be serialized, while operations on
    # different networks can still run in parallel. The lock will be released by
    # COMMIT or ROLLBACK.
    dbnetwork.lock_row()

    startip = dbnetwork.first_usable_host

    used_ips = session.query(ARecord.ip)
    used_ips = used_ips.filter_by(network=dbnetwork)
    used_ips = used_ips.filter(ARecord.ip >= startip)

    full_set = set(range(int(startip), int(dbnetwork.broadcast)))
    used_set = set([int(item.ip) for item in used_ips])
    free_set = full_set - used_set

    if not free_set:
        raise ArgumentError("No available IP addresses found on "
                            "network %s." % str(dbnetwork.network))

    if ipalgorithm is None or ipalgorithm == 'lowest':
        # Select the lowest available address
        ip = IPv4Address(min(free_set))
    elif ipalgorithm == 'highest':
        # Select the highest available address
        ip = IPv4Address(max(free_set))
    elif ipalgorithm == 'max':
        # Return the max. used address + 1
        if not used_set:
            # Avoids ValueError being thrown when used_set is empty
            ip = IPv4Address(min(free_set))
        else:
            next = max(used_set)
            if not next + 1 in free_set:
                raise ArgumentError("Failed to find an IP that is suitable "
                                    "for --ipalgorithm=max.  Try an other "
                                    "algorithm as there are still some free "
                                    "addresses.")
            ip = IPv4Address(next + 1)
    else:
        raise ArgumentError("Unknown algorithm %s." % ipalgorithm)

    if audit_results is not None:
        if dbinterface:
            logger.info("Selected IP address {0!s} for {1:l}".format(
                ip, dbinterface))
        else:
            logger.info("Selected IP address %s" % ip)
        audit_results.append(('ip', ip))

    return ip
Пример #22
0
    def render(self, session, logger, machine, chassis, switch, interface,
               fqdn, ip, label, keep_dns, network_environment, **kwargs):

        if machine:
            hwtype = 'machine'
            hwname = machine
        elif chassis:
            hwtype = 'chassis'
            hwname = chassis
        elif switch:
            hwtype = 'switch'
            hwname = switch

        dbhw_ent = HardwareEntity.get_unique(session,
                                             hwname,
                                             hardware_type=hwtype,
                                             compel=True)
        dbinterface = Interface.get_unique(session,
                                           hardware_entity=dbhw_ent,
                                           name=interface,
                                           compel=True)
        dbnet_env = NetworkEnvironment.get_unique_or_default(
            session, network_environment)

        oldinfo = DSDBRunner.snapshot_hw(dbhw_ent)

        if fqdn:
            dbdns_rec = ARecord.get_unique(
                session,
                fqdn=fqdn,
                dns_environment=dbnet_env.dns_environment,
                compel=True)
            ip = dbdns_rec.ip

        addr = None
        if ip:
            addr = first_of(dbinterface.assignments, lambda x: x.ip == ip)
            if not addr:
                raise ArgumentError(
                    "{0} does not have IP address {1} assigned to "
                    "it.".format(dbinterface, ip))
        elif label is not None:
            addr = first_of(dbinterface.assignments,
                            lambda x: x.label == label)
            if not addr:
                raise ArgumentError("{0} does not have an address with label "
                                    "{1}.".format(dbinterface, label))

        if not addr:
            raise ArgumentError("Please specify the address to be removed "
                                "using either --ip, --label, or --fqdn.")

        dbnetwork = addr.network
        ip = addr.ip

        if dbnetwork.network_environment != dbnet_env:
            raise ArgumentError("The specified address lives in {0:l}, not in "
                                "{1:l}.  Use the --network_environment option "
                                "to select the correct environment.".format(
                                    dbnetwork.network_environment, dbnet_env))

        # Forbid removing the primary name
        if ip == dbhw_ent.primary_ip:
            raise ArgumentError("The primary IP address of a hardware entity "
                                "cannot be removed.")

        dbinterface.assignments.remove(addr)

        # Check if the address was assigned to multiple interfaces, and remove
        # the DNS entries if this was the last use
        q = session.query(AddressAssignment)
        q = q.filter_by(network=dbnetwork)
        q = q.filter_by(ip=ip)
        other_uses = q.all()
        if not other_uses and not keep_dns:
            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=dbnet_env.dns_environment)
            map(delete_dns_record, q.all())

        session.flush()

        dbhost = getattr(dbhw_ent, "host", None)
        if dbhost:
            plenary_info = PlenaryHost(dbhost, logger=logger)
            key = plenary_info.get_write_key()
            try:
                lock_queue.acquire(key)
                try:
                    plenary_info.write(locked=True)
                except IncompleteError:
                    # FIXME: if this command is used after "add host" but before
                    # "make", then writing out the template will fail due to
                    # required services not being assigned. Ignore this error
                    # for now.
                    plenary_info.restore_stash()

                dsdb_runner = DSDBRunner(logger=logger)
                dsdb_runner.update_host(dbhw_ent, oldinfo)

                if not other_uses and keep_dns:
                    q = session.query(ARecord)
                    q = q.filter_by(network=dbnetwork)
                    q = q.filter_by(ip=ip)
                    dbdns_rec = q.first()
                    dsdb_runner.add_host_details(dbdns_rec.fqdn, ip)

                dsdb_runner.commit_or_rollback("Could not add host to DSDB")
            except:
                plenary_info.restore_stash()
                raise
            finally:
                lock_queue.release(key)
        else:
            dsdb_runner = DSDBRunner(logger=logger)
            dsdb_runner.update_host(dbhw_ent, oldinfo)
            dsdb_runner.commit_or_rollback("Could not add host to DSDB")

        return
Пример #23
0
    def render(self, session, logger, fqdn, ip, reverse_ptr, dns_environment,
               network_environment, comments, **arguments):
        dbnet_env, dbdns_env = get_net_dns_env(session, network_environment,
                                               dns_environment)
        dbdns_rec = ARecord.get_unique(session, fqdn=fqdn,
                                       dns_environment=dbdns_env, compel=True)

        old_ip = dbdns_rec.ip
        old_comments = dbdns_rec.comments

        if ip:
            if dbdns_rec.hardware_entity:
                raise ArgumentError("{0} is a primary name, and its IP address "
                                    "cannot be changed.".format(dbdns_rec))

            if dbdns_rec.assignments:
                ifaces = ", ".join(["%s/%s" % (addr.interface.hardware_entity,
                                               addr.interface)
                                    for addr in dbdns_rec.assignments])
                raise ArgumentError("{0} is already used by the following "
                                    "interfaces, and its IP address cannot be "
                                    "changed: {1!s}."
                                    .format(dbdns_rec, ifaces))

            dbnetwork = get_net_id_from_ip(session, ip, dbnet_env)

            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=dbdns_env)
            existing = q.first()
            if existing:
                raise ArgumentError("IP address {0!s} is already used by "
                                    "{1:l}." .format(ip, existing))

            dbdns_rec.network = dbnetwork
            old_ip = dbdns_rec.ip
            dbdns_rec.ip = ip

        if reverse_ptr:
            old_reverse = dbdns_rec.reverse_ptr
            set_reverse_ptr(session, logger, dbdns_rec, reverse_ptr)
            if old_reverse and old_reverse != dbdns_rec.reverse_ptr:
                delete_target_if_needed(session, old_reverse)

        if comments:
            dbdns_rec.comments = comments

        session.flush()

        if dbdns_env.is_default and (dbdns_rec.ip != old_ip or
                                     dbdns_rec.comments != old_comments):
            dsdb_runner = DSDBRunner(logger=logger)
            dsdb_runner.update_host_details(dbdns_rec.fqdn, new_ip=dbdns_rec.ip,
                                            old_ip=old_ip,
                                            new_comments=dbdns_rec.comments,
                                            old_comments=old_comments)
            dsdb_runner.commit_or_rollback()

        return
Пример #24
0
def generate_ip(session, logger, dbinterface, ip=None, ipfromip=None,
                ipfromsystem=None, autoip=None, ipalgorithm=None, compel=False,
                network_environment=None, audit_results=None, **kwargs):
    ip_options = [ip, ipfromip, ipfromsystem, autoip]
    numopts = sum([1 if opt else 0 for opt in ip_options])
    if numopts > 1:
        raise ArgumentError("Only one of --ip, --ipfromip, --ipfromsystem "
                            "and --autoip can be specified.")
    elif numopts == 0:
        if compel:
            raise ArgumentError("Please specify one of the --ip, --ipfromip, "
                                "--ipfromsystem, and --autoip parameters.")
        return None

    if ip:
        return ip

    dbsystem = None
    dbnetwork = None
    if autoip:
        if not dbinterface:
            raise ArgumentError("No interface available to automatically "
                                "generate an IP address.")
        if dbinterface.port_group:
            # This could either be an interface from a virtual machine
            # or an interface on an ESX vmhost.
            dbcluster = None
            if getattr(dbinterface.hardware_entity, "cluster", None):
                # VM
                dbcluster = dbinterface.hardware_entity.cluster
            elif getattr(dbinterface.hardware_entity, "host", None):
                dbcluster = dbinterface.hardware_entity.host.cluster
            if not dbcluster:
                raise ArgumentError("Can only automatically assign an IP "
                                    "address to an interface with a port "
                                    "group on virtual machines or ESX hosts.")
            if not dbcluster.switch:
                raise ArgumentError("Cannot automatically assign an IP "
                                    "address to an interface with a port group "
                                    "since {0} is not associated with a "
                                    "switch.".format(dbcluster))
            vlan_id = VlanInfo.get_vlan_id(session, dbinterface.port_group)
            dbnetwork = ObservedVlan.get_network(session, vlan_id=vlan_id,
                                                 switch=dbcluster.switch,
                                                 compel=ArgumentError)
        elif dbinterface.mac:
            q = session.query(ObservedMac)
            q = q.filter_by(mac_address=dbinterface.mac)
            q = q.order_by(desc(ObservedMac.last_seen))
            dbom = q.first()
            if not dbom:
                raise ArgumentError("No switch found in the discovery table "
                                    "for MAC address %s." % dbinterface.mac)
            if not dbom.switch.primary_ip:
                raise ArgumentError("{0} does not have a primary IP address "
                                    "to use for network "
                                    "selection.".format(dbom.switch))
            dbnetwork = get_net_id_from_ip(session, dbom.switch.primary_ip)
        else:
            raise ArgumentError("{0} has neither a MAC address nor port group "
                                "information, it is not possible to generate "
                                "an IP address automatically."
                                .format(dbinterface))

    if ipfromsystem:
        # Assumes one system entry, not necessarily correct.
        dbdns_rec = ARecord.get_unique(session, fqdn=ipfromsystem, compel=True)
        dbnetwork = dbdns_rec.network

    if ipfromip:
        # determine network
        dbnetwork = get_net_id_from_ip(session, ipfromip, network_environment)

    if not dbnetwork:
        raise ArgumentError("Could not determine network to use for %s." %
                            dbsystem.fqdn)

    # When there are e.g. multiple "add manager --autoip" operations going on in
    # parallel, we must ensure that they won't try to use the same IP address.
    # This query places a database lock on the network, which means IP address
    # generation within a network will be serialized, while operations on
    # different networks can still run in parallel. The lock will be released by
    # COMMIT or ROLLBACK.
    dbnetwork.lock_row()

    startip = dbnetwork.first_usable_host

    used_ips = session.query(ARecord.ip)
    used_ips = used_ips.filter_by(network=dbnetwork)
    used_ips = used_ips.filter(ARecord.ip >= startip)

    full_set = set(range(int(startip), int(dbnetwork.broadcast)))
    used_set = set([int(item.ip) for item in used_ips])
    free_set = full_set - used_set

    if not free_set:
        raise ArgumentError("No available IP addresses found on "
                            "network %s." % str(dbnetwork.network))

    if ipalgorithm is None or ipalgorithm == 'lowest':
        # Select the lowest available address
        ip = IPv4Address(min(free_set))
    elif ipalgorithm == 'highest':
        # Select the highest available address
        ip = IPv4Address(max(free_set))
    elif ipalgorithm == 'max':
        # Return the max. used address + 1
        if not used_set:
            # Avoids ValueError being thrown when used_set is empty
            ip = IPv4Address(min(free_set))
        else:
            next = max(used_set)
            if not next + 1 in free_set:
                raise ArgumentError("Failed to find an IP that is suitable "
                                    "for --ipalgorithm=max.  Try an other "
                                    "algorithm as there are still some free "
                                    "addresses.")
            ip = IPv4Address(next + 1)
    else:
        raise ArgumentError("Unknown algorithm %s." % ipalgorithm)

    if audit_results is not None:
        if dbinterface:
            logger.info("Selected IP address {0!s} for {1:l}"
                        .format(ip, dbinterface))
        else:
            logger.info("Selected IP address %s" % ip)
        audit_results.append(('ip', ip))

    return ip