예제 #1
0
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))
예제 #2
0
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)