Exemple #1
0
def pre_init_checks(session, device_id) -> Device:
    """Find device with device_id and check that it's ready for init, returns
    Device object or raises exception"""
    # Check that we can find device and that it's in the correct state to start init
    dev: Device = session.query(Device).filter(
        Device.id == device_id).one_or_none()
    if not dev:
        raise ValueError(f"No device with id {device_id} found")
    if dev.state != DeviceState.DISCOVERED:
        raise DeviceStateException(
            "Device must be in state DISCOVERED to begin init")
    old_hostname = dev.hostname
    # Perform connectivity check
    nr = cnaas_nms.confpush.nornir_helper.cnaas_init()
    nr_old_filtered = nr.filter(name=old_hostname)
    try:
        nrresult_old = nr_old_filtered.run(task=napalm_get, getters=["facts"])
    except Exception as e:
        raise ConnectionCheckError(
            f"Failed to connect to device_id {device_id}: {str(e)}")
    if nrresult_old.failed:
        print_result(nrresult_old)
        raise ConnectionCheckError(
            f"Failed to connect to device_id {device_id}")
    return dev
def init_access_device_step2(device_id: int,
                             iteration: int = -1) -> NornirJobResult:
    # step4+ in apjob: if success, update management ip and device state, trigger external stuff?
    with sqla_session() as session:
        dev = session.query(Device).filter(Device.id == device_id).one()
        if dev.state != DeviceState.INIT:
            logger.error("Device with ID {} got to init step2 but is in incorrect state: {}".\
                         format(device_id, dev.state.name))
            raise DeviceStateException(
                "Device must be in state INIT to continue init step 2")
        hostname = dev.hostname
    nr = cnaas_nms.confpush.nornir_helper.cnaas_init()
    nr_filtered = nr.filter(name=hostname)

    nrresult = nr_filtered.run(task=networking.napalm_get, getters=["facts"])

    if nrresult.failed:
        next_job_id = schedule_init_access_device_step2(device_id, iteration)
        if next_job_id:
            return NornirJobResult(nrresult=nrresult, next_job_id=next_job_id)
        else:
            return NornirJobResult(nrresult=nrresult)
    try:
        facts = nrresult[hostname][0].result['facts']
        found_hostname = facts['hostname']
    except:
        raise InitError("Could not log in to device during init step 2")
    if hostname != found_hostname:
        raise InitError("Newly initialized device presents wrong hostname")

    with sqla_session() as session:
        dev: Device = session.query(Device).filter(
            Device.id == device_id).one()
        dev.state = DeviceState.MANAGED
        dev.device_type = DeviceType.ACCESS
        dev.synchronized = False
        #TODO: remove dhcp_ip ?

    try:
        update_interfacedb(hostname, replace=True)
    except Exception as e:
        logger.exception(
            "Exception while updating interface database for device {}: {}".\
            format(hostname, str(e)))

    return NornirJobResult(nrresult=nrresult)
Exemple #3
0
def init_device_step2(device_id: int, iteration: int = -1,
                      job_id: Optional[str] = None,
                      scheduled_by: Optional[str] = None) -> \
                      NornirJobResult:
    logger = get_logger()
    # step4+ in apjob: if success, update management ip and device state, trigger external stuff?
    with sqla_session() as session:
        dev = session.query(Device).filter(Device.id == device_id).one()
        if dev.state != DeviceState.INIT:
            logger.error("Device with ID {} got to init step2 but is in incorrect state: {}".\
                         format(device_id, dev.state.name))
            raise DeviceStateException(
                "Device must be in state INIT to continue init step 2")
        hostname = dev.hostname
        devtype: DeviceType = dev.device_type
    nr = cnaas_nms.confpush.nornir_helper.cnaas_init()
    nr_filtered = nr.filter(name=hostname)

    nrresult = nr_filtered.run(task=napalm_get, getters=["facts"])

    if nrresult.failed:
        next_job_id = schedule_init_device_step2(device_id, iteration,
                                                 scheduled_by)
        if next_job_id:
            return NornirJobResult(nrresult=nrresult, next_job_id=next_job_id)
        else:
            return NornirJobResult(nrresult=nrresult)
    try:
        facts = nrresult[hostname][0].result['facts']
        found_hostname = facts['hostname']
    except:
        raise InitError("Could not log in to device during init step 2")
    if hostname != found_hostname:
        raise InitError("Newly initialized device presents wrong hostname")

    with sqla_session() as session:
        dev: Device = session.query(Device).filter(
            Device.id == device_id).one()
        dev.state = DeviceState.MANAGED
        dev.synchronized = False
        set_facts(dev, facts)
        management_ip = dev.management_ip
        dev.dhcp_ip = None

    # Plugin hook: new managed device
    # Send: hostname , device type , serial , platform , vendor , model , os version
    try:
        pmh = PluginManagerHandler()
        pmh.pm.hook.new_managed_device(hostname=hostname,
                                       device_type=devtype.name,
                                       serial_number=facts['serial_number'],
                                       vendor=facts['vendor'],
                                       model=facts['model'],
                                       os_version=facts['os_version'],
                                       management_ip=str(management_ip))
    except Exception as e:
        logger.exception(
            "Error while running plugin hooks for new_managed_device: ".format(
                str(e)))

    return NornirJobResult(nrresult=nrresult)
Exemple #4
0
def init_access_device_step1(device_id: int,
                             new_hostname: str) -> NornirJobResult:
    """Initialize access device for management by CNaaS-NMS

    Args:
        hostname (str): Hostname of device to initialize

    Returns:
        Nornir result object

    Raises:
        DeviceStateException
    """
    # Check that we can find device and that it's in the correct state to start init
    with sqla_session() as session:
        dev: Device = session.query(Device).filter(
            Device.id == device_id).one()
        if dev.state != DeviceState.DISCOVERED:
            raise DeviceStateException(
                "Device must be in state DISCOVERED to begin init")
        old_hostname = dev.hostname
    # Perform connectivity check
    nr = cnaas_nms.confpush.nornir_helper.cnaas_init()
    nr_old_filtered = nr.filter(name=old_hostname)
    try:
        nrresult_old = nr_old_filtered.run(task=networking.napalm_get,
                                           getters=["facts"])
    except Exception as e:
        raise ConnectionCheckError(
            f"Failed to connect to device_id {device_id}: {str(e)}")
    if nrresult_old.failed:
        raise ConnectionCheckError(
            f"Failed to connect to device_id {device_id}")

    cnaas_nms.confpush.get.update_linknets(old_hostname)
    uplinks = []
    neighbor_hostnames = []
    with sqla_session() as session:
        dev = session.query(Device).filter(
            Device.hostname == old_hostname).one()
        for neighbor_d in dev.get_neighbors(session):
            if neighbor_d.device_type == DeviceType.DIST:
                local_if = dev.get_link_to_local_ifname(session, neighbor_d)
                if local_if:
                    uplinks.append({'ifname': local_if})
                    neighbor_hostnames.append(neighbor_d.hostname)
        logger.debug("Uplinks for device {} detected: {} neighbor_hostnames: {}".\
                     format(device_id, uplinks, neighbor_hostnames))
        #TODO: check compatability, same dist pair and same ports on dists
        mgmtdomain = cnaas_nms.db.helper.find_mgmtdomain(
            session, neighbor_hostnames)
        if not mgmtdomain:
            raise Exception(
                "Could not find appropriate management domain for uplink peer devices: {}"
                .format(neighbor_hostnames))
        mgmt_ip = mgmtdomain.find_free_mgmt_ip(session)
        if not mgmt_ip:
            raise Exception(
                "Could not find free management IP for management domain {}".
                format(mgmtdomain.id))
        mgmt_gw_ipif = IPv4Interface(mgmtdomain.ipv4_gw)
        device_variables = {
            'mgmt_ipif':
            IPv4Interface('{}/{}'.format(mgmt_ip,
                                         mgmt_gw_ipif.network.prefixlen)),
            'uplinks':
            uplinks,
            'mgmt_vlan_id':
            mgmtdomain.vlan,
            'mgmt_gw':
            mgmt_gw_ipif.ip
        }
        dev = session.query(Device).filter(Device.id == device_id).one()
        dev.state = DeviceState.INIT
        dev.hostname = new_hostname
        session.commit()
        hostname = dev.hostname

    nr = cnaas_nms.confpush.nornir_helper.cnaas_init()
    nr_filtered = nr.filter(name=hostname)

    # step2. push management config
    try:
        nrresult = nr_filtered.run(task=push_base_management,
                                   device_variables=device_variables)
    except Exception as e:
        pass  # ignore exception, we expect to loose connectivity.
        # sometimes we get no exception here, but it's saved in result
        # other times we get socket.timeout, pyeapi.eapilib.ConnectionError or
        # napalm.base.exceptions.ConnectionException to handle here?
    if not nrresult.failed:
        raise  #we don't expect success here

    print_result(nrresult)

    with sqla_session() as session:
        dev = session.query(Device).filter(Device.id == device_id).one()
        dev.management_ip = device_variables['mgmt_ipif'].ip

    # step3. register apscheduler job that continues steps

    scheduler = Scheduler()
    next_job = scheduler.add_onetime_job(
        'cnaas_nms.confpush.init_device:init_access_device_step2',
        when=0,
        kwargs={
            'device_id': device_id,
            'iteration': 1
        })

    logger.debug(f"Step 2 scheduled as ID {next_job.id}")

    return NornirJobResult(nrresult=nrresult, next_job_id=next_job.id)