def sync_check_hash(task, force=False, job_id=None): """ Start the task which will compare device configuration hashes. Args: task: Nornir task force: Ignore device hash """ set_thread_data(job_id) logger = get_logger() if force is True: return with sqla_session() as session: stored_hash = Device.get_config_hash(session, task.host.name) if stored_hash is None: return task.host.open_connection("napalm", configuration=task.nornir.config) res = task.run(task=napalm_get, getters=["config"]) task.host.close_connection("napalm") running_config = dict(res.result)['config']['running'].encode() if running_config is None: raise Exception('Failed to get running configuration') hash_obj = sha256(running_config) running_hash = hash_obj.hexdigest() if stored_hash != running_hash: raise Exception('Device {} configuration is altered outside of CNaaS!'.format(task.host.name))
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)