def update_config_hash(task): logger = get_logger() try: res = task.run(task=napalm_get, getters=["config"]) if not isinstance(res, MultiResult) or len(res) != 1 or not isinstance(res[0].result, dict) \ or 'config' not in res[0].result: raise Exception("Unable to get config from device") new_config_hash = calc_config_hash(task.host.name, res[0].result['config']['running']) if not new_config_hash: raise ValueError("Empty config hash") except Exception as e: logger.exception("Unable to get config hash: {}".format(str(e))) raise e else: with sqla_session() as session: Device.set_config_hash(session, task.host.name, new_config_hash) logger.debug("Config hash for {} updated to {}".format(task.host.name, new_config_hash))
def sync_devices(hostname: Optional[str] = None, device_type: Optional[str] = None, dry_run: bool = True, force: bool = False) -> NornirJobResult: """Synchronize devices to their respective templates. If no arguments are specified then synchronize all devices that are currently out of sync. Args: hostname: Specify a single host by hostname to synchronize device_type: Specify a device type to synchronize Returns: NornirJobResult """ nr = cnaas_nms.confpush.nornir_helper.cnaas_init() if hostname: nr_filtered = nr.filter(name=hostname).filter(managed=True) elif device_type: nr_filtered = nr.filter(F(groups__contains='T_' + device_type)) # device type else: nr_filtered = nr.filter(synchronized=False).filter( managed=True) # all unsynchronized devices device_list = list(nr_filtered.inventory.hosts.keys()) logger.info( "Device(s) selected for synchronization: {}".format(device_list)) alterned_devices = [] for device in device_list: stored_config_hash = Device.get_config_hash(device) if stored_config_hash is None: continue current_config_hash = get_running_config_hash(device) if current_config_hash is None: raise Exception('Failed to get configuration hash') if stored_config_hash != current_config_hash: logger.info( "Device {} configuration is altered outside of CNaaS!".format( device)) alterned_devices.append(device) if alterned_devices != [] and force is False: raise Exception( 'Configuration for {} is altered outside of CNaaS'.format( ', '.join(alterned_devices))) try: nrresult = nr_filtered.run(task=push_sync_device, dry_run=dry_run) print_result(nrresult) except Exception as e: logger.exception("Exception while synchronizing devices: {}".format( str(e))) return NornirJobResult(nrresult=nrresult) failed_hosts = list(nrresult.failed_hosts.keys()) if not dry_run: for key in nrresult.keys(): if key in failed_hosts: continue new_config_hash = get_running_config_hash(key) if new_config_hash is None: raise Exception('Failed to get configuration hash') Device.set_config_hash(key, new_config_hash) with sqla_session() as session: for hostname in device_list: if hostname in failed_hosts: logger.error( "Synchronization of device '{}' failed".format( hostname)) continue dev: Device = session.query(Device).filter( Device.hostname == hostname).one() dev.synchronized = True if nrresult.failed: logger.error("Not all devices were successfully synchronized") return NornirJobResult(nrresult=nrresult)