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)
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)
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)