Ejemplo n.º 1
0
    def get_vlans(task: Task) -> Result:
        """Get a list of vlans from the device using netmiko and genie parser.

        Args:
            task (Task): Nornir Task

        Returns:
            Result: Nornir Result object with a dict as a result containing the vlans
            The format of the result but must be similar to Vlans defined in network_importer.processors.get_vlans
        """
        LOGGER.debug("Executing get_vlans for %s (%s)", task.host.name, task.host.platform)

        try:
            results = task.run(task=netmiko_send_command, command_string="show vlan", use_genie=True)
        except NornirSubTaskError:
            LOGGER.debug(
                "An exception occured while pulling the vlans information",
                exc_info=True,
            )
            return Result(host=task.host, failed=True)

        if not isinstance(results[0].result, dict) or "vlans" not in results[0].result:
            LOGGER.warning("%s | No vlans information returned", task.host.name)
            return Result(host=task.host, result=False)

        results = convert_cisco_genie_vlans(device_name=task.host.name, data=results[0].result)
        return Result(host=task.host, result=results.dict())
Ejemplo n.º 2
0
    def get_neighbors(task: Task) -> Result:
        """Get a list of neighbors from the device.

        Args:
            task (Task): Nornir Task

        Returns:
            Result: Nornir Result object with a dict as a result containing the neighbors
            The format of the result but must be similar to Neighbors defined in network_importer.processors.get_neighbors
        """
        LOGGER.debug("Executing get_neighbor for %s (%s)", task.host.name, task.host.platform)

        if config.SETTINGS.main.import_cabling == "lldp":
            command = "show lldp neighbors detail"
            converter = convert_cisco_genie_lldp_neighbors_details
            cmd_type = "LLDP"
        elif config.SETTINGS.main.import_cabling == "cdp":
            command = "show cdp neighbors detail"
            converter = convert_cisco_genie_cdp_neighbors_details
            cmd_type = "CDP"
        else:
            return Result(host=task.host, failed=True)

        try:
            result = task.run(task=netmiko_send_command, command_string=command, use_genie=True)
        except NornirSubTaskError:
            LOGGER.debug("An exception occured while pulling %s data", cmd_type, exc_info=True)
            return Result(host=task.host, failed=True)

        if result[0].failed:
            return result

        results = converter(device_name=task.host.name, data=result[0].result)
        return Result(host=task.host, result=results.dict())
Ejemplo n.º 3
0
def check_if_reachable(task: Task) -> Result:
    """Check if a device is reachable by doing a TCP ping it on port 22.

    Will change the status of the variable `host.is_reachable` based on the results

    Args:
      task: Nornir Task

    Returns:
       Result: Nornir Result
    """
    port_to_check = 22
    try:
        results = task.run(task=tcp_ping, ports=[port_to_check])
    except:  # noqa: E722 # pylint: disable=bare-except
        LOGGER.debug(
            "An exception occured while running the reachability test (tcp_ping)",
            exc_info=True,
        )
        return Result(host=task.host, failed=True)

    is_reachable = results[0].result[port_to_check]

    if not is_reachable:
        LOGGER.debug("%s | device is not reachable on port %s", task.host.name,
                     port_to_check)
        task.host.is_reachable = False
        task.host.not_reachable_reason = f"device not reachable on port {port_to_check}"
        task.host.status = "fail-ip"

    return Result(host=task.host, result=is_reachable)
Ejemplo n.º 4
0
def configure_vlan(task, vlan_id, vlan_name):
    result = task.run(
        task=networking.netmiko_send_command,
        command_string=f"show vlan brief | i {vlan_id}",
    )
    if result.result:
        existing_vlan_id = result.result.split()[0]
        existing_vlan_name = result.result.split()[1]
        if existing_vlan_id == vlan_id and existing_vlan_name == vlan_name:
            result = f"Vlan {vlan_id} with name {vlan_name} exists, nothing to do!"
            changed = False
            failed = False
            return Result(host=task.host,
                          result=result,
                          changed=changed,
                          failed=failed)
    else:
        result = task.run(
            task=networking.netmiko_send_config,
            config_commands=[f"vlan {vlan_id}", f"name {vlan_name}"],
        )
        result = f"Configured vlan {vlan_id} with name {vlan_name}!"
        changed = True
        # Note that we can set the 'failed' var to False here because even if the task
        # failed, that will be reflected in the sub-task (in the multi-result)!
        failed = False
        return Result(host=task.host,
                      result=result,
                      changed=changed,
                      failed=failed)
Ejemplo n.º 5
0
    def _render_config(task, template_name, template_path=None):
        from jinja2 import Environment, FileSystemLoader, StrictUndefined
        logger.info(f"{task.host}: Rendering Config")

        if not template_path:
            template_path = os.path.join(os.getcwd(),
                                         f'templates/{task.host.platform}')

        env = Environment(
            loader=FileSystemLoader(template_path),
            undefined=StrictUndefined,
            trim_blocks=False,
        )

        result = task.run(task=template_file,
                          name='Render Device Configuration',
                          template=f'{template_name}.j2',
                          jinja_env=env,
                          path=template_path,
                          **task.host)

        if not result:
            logger.info(f"{task.host}: Failed to render configg")
            return Result(host=task.host, failed=True, changed=False)

        config = result.result
        logger.info(f"{task.host}: Config Rendered")

        return Result(host=task.host,
                      result=config,
                      failed=False,
                      changed=False)
Ejemplo n.º 6
0
def device_save_hostvars(task: Task) -> Result:
    """Save the device hostvars into a yaml file.

    Args:
      task (Task): Nornir Task

    Returns:
      Result: Nornir Result
    """
    if not task.host.data["obj"].hostvars:
        return Result(host=task.host)

    # Save device hostvars in file
    if not os.path.exists(
            f"{config.SETTINGS.main.hostvars_directory}/{task.host.name}"):
        os.makedirs(
            f"{config.SETTINGS.main.hostvars_directory}/{task.host.name}")
        LOGGER.debug("Directory %s/%s was missing, created it",
                     config.SETTINGS.main.hostvars_directory, task.host.name)

    with open(
            f"{config.SETTINGS.main.hostvars_directory}/{task.host.name}/network_importer.yaml",
            "w",
    ) as out_file:
        out_file.write(
            yaml.dump(task.host.data["obj"].hostvars,
                      default_flow_style=False))
        LOGGER.debug(
            "%s - Host variables saved in %s/%s/network_importer.yaml",
            task.host.name,
            config.SETTINGS.main.hostvars_directory,
            task.host.name,
        )

    return Result(host=task.host)
Ejemplo n.º 7
0
    def get_vlans(task: Task) -> Result:
        """Get a list of vlans from the device.

        Args:
            task (Task): Nornir Task

        Returns:
            Result: Nornir Result object with a dict as a result containing the vlans
            The format of the result but must be similar to Vlans defined in network_importer.processors.get_vlans
        """
        results = Vlans()

        nr_device = task.host.get_connection("napalm", task.nornir.config)
        eos_device = nr_device.device
        results = eos_device.run_commands(["show vlan"])

        if not isinstance(results[0], dict) or "vlans" not in results[0]:
            LOGGER.warning("%s | No vlans information returned",
                           task.host.name)
            return Result(host=task.host, result=False)

        for vid, data in results[0]["vlans"].items():
            results.vlans.append(Vlan(name=data["name"], id=vid))

        return Result(host=task.host, result=results)
Ejemplo n.º 8
0
def device_save_hostvars(task: Task) -> Result:
    """
    Save the device hostvars into a yaml file

    Args:
      task: Task:

    Returns:
      Result
    """

    if not task.host.data["obj"].hostvars:
        return Result(host=task.host)

    # Save device hostvars in file
    if not os.path.exists(
            f"{config.main['hostvars_directory']}/{task.host.name}"):
        os.makedirs(f"{config.main['hostvars_directory']}/{task.host.name}")
        logger.debug(
            f"Directory {config.main['hostvars_directory']}/{task.host.name} was missing, created it"
        )

    with open(
            f"{config.main['hostvars_directory']}/{task.host.name}/network_importer.yaml",
            "w",
    ) as out_file:
        out_file.write(
            yaml.dump(task.host.data["obj"].hostvars,
                      default_flow_style=False))
        logger.debug(
            f"{task.host.name} - Host variables saved in {config.main['hostvars_directory']}/{task.host.name}/network_importer.yaml"
        )

    return Result(host=task.host)
Ejemplo n.º 9
0
def ping_until_up(task):
    """
    Ping the device every 5 seconds until back up. If pings
    stop responding after 20 minutes, log error message to terminal
    """
    print(colored(f'Waiting for {task.host.name} to reboot', 'yellow'))
    seconds = 1200
    while True:
        response = subprocess.call(['ping', '-c', '1', task.host.name],
                                   stdout=subprocess.PIPE)
        if response != 0:
            sleep(5)
            seconds = seconds - 5
            if seconds <= 0:
                result = f"***** WARNING ***** {task.host} didn't respond to a ping within 20 minutes"
                print(colored(result, 'red'))
                result = Result(host=task.host,
                                changed=True,
                                Failed=True,
                                result=result)
                break
            else:
                continue
        elif response == 0:
            result = f'{task.host.name} is now responding to ping. The device was down for about {1200 - seconds} seconds.'
            print(colored(result, 'green'))
            result = Result(host=task.host,
                            changed=False,
                            Failed=False,
                            result=result)
            break
    return result
Ejemplo n.º 10
0
def as3_post(task: Task, as3_tenant: str) -> Result:
    failover_status = task.run(
        name="Get failover status", task=bigip_cm_failover_status
    ).result

    if failover_status == "ACTIVE":
        task.run(
            name="AS3 POST",
            task=atc,
            atc_delay=0,
            atc_method="POST",
            atc_retries=3,
            atc_service="AS3",
            as3_tenant=as3_tenant,
            atc_declaration_file=task.host["appsvcs"][as3_tenant][
                "atc_declaration_file"
            ],
        )

        task.run(
            name="Synchronize the devices",
            task=bigip_cm_config_sync,
            delay=0,
            device_group=task.host["device_group"],
            retries=3,
        )

        return Result(
            host=task.host,
            result="ACTIVE device, AS3 declaration successfully deployed.",
        )
    else:
        return Result(host=task.host, result="STANDBY device, skipped.")
Ejemplo n.º 11
0
def _wait_task(
    task: Task,
    atc_task_endpoint: str,
    atc_task_id: str,
    atc_delay: int = 10,
    atc_retries: int = 30,
) -> Result:
    client = f5_rest_client(task)
    host = f"{task.host.hostname}:{task.host.port}"

    for _i in range(0, atc_retries):
        atc_task_resp = client.get(
            f"https://{host}{atc_task_endpoint}/{atc_task_id}"
        ).json()

        if "results" in atc_task_resp:
            message = atc_task_resp["results"][0]["message"]
        else:
            message = atc_task_resp["result"]["message"]

        if message in ["in progress", "processing"]:
            pass
        elif message == "success":
            return Result(host=task.host, changed=True, result=message)
        elif message == "no change":
            return Result(host=task.host, result=message)
        else:
            raise Exception("The task failed.")
        time.sleep(atc_delay)

    raise Exception("The task has reached maximum retries.")
Ejemplo n.º 12
0
def update_configuration(  # pylint: disable=C0330
        task: Task,
        configs_directory,
        config_extension="txt") -> Result:
    """
    Collect running configurations on all devices

    Supported Devices:
        Default: Napalm (TODO)
        Cisco: Netmiko

    Args:
      task: Task:
      configs_directory:
      config_extension: (Default value = "txt")

    Returns:

    """

    config_filename = f"{configs_directory}/{task.host.name}.{config_extension}"

    new_config = None
    current_md5 = None

    if os.path.exists(config_filename):
        current_config = Path(config_filename).read_text()
        previous_md5 = hashlib.md5(current_config.encode("utf-8")).hexdigest()

    try:
        results = task.run(task=napalm_get,
                           getters=["config"],
                           retrieve="running")
    except:
        logger.debug("An exception occured while pulling the configuration",
                     exc_info=True)
        return Result(host=task.host, failed=True)

    if results.failed:
        return Result(host=task.host, failed=True)

    new_config = results[0].result["config"]["running"]

    # Currently the configuration is going to be different everytime because there is a timestamp on it
    # Will need to do some clean up
    with open(config_filename, "w") as config_:
        config_.write(new_config)

    new_md5 = hashlib.md5(new_config.encode("utf-8")).hexdigest()
    changed = False

    if current_md5 and current_md5 == new_md5:
        logger.debug(
            f"{task.host.name} | Latest config file already present ... ")

    else:
        logger.info(f"{task.host.name} | Configuration file updated ")
        changed = True

    return Result(host=task.host, result=True, changed=changed)
Ejemplo n.º 13
0
def upgrade_os(task: Task, version: str) -> Result:
    # we use task get_verion to retrieve current OS running
    result = task.run(task=get_version)

    # if the version matches what we want to install we are done!
    if result.result["full_version"] == version:
        return Result(host=task.host, result="nothing to do!!!")

    # otherwise we call install_os_version task to install the image
    task.run(task=install_os_version, version=version)
    return Result(host=task.host, changed=True, result="success!!!")
Ejemplo n.º 14
0
def query_device_info_from_nautobot(task: Task) -> Result:
    """Nornir Task to query the device information from Nautobot.

    Currently this task will pull both the device information but th goal is to pull additional information
    and return everything in a single dict
    TODO add logic to pull interfaces as well
    TODO add logic to pull ip addresses as well

    Args:
        task (Task): Nornir Task with a valid network device

    Returns:
        Result: Nornir Result object with the result in a dict format
    """
    inventory_settings = InventorySettings(
        **config.SETTINGS.inventory.settings)
    nautobot = pynautobot.api(url=inventory_settings.address,
                              token=inventory_settings.token)

    # Check for SSL Verification, set it to false if not. Else set to true
    if not inventory_settings.verify_ssl:
        # No manual session is required for this, pynautobot will automatically create one
        nautobot.http_session.verify = False
    else:
        nautobot.http_session.verify = True

    # Set a Results dictionary
    results = {
        "device": None,
        "interfaces": None,
    }

    # Get the device based on the filter
    device = nautobot.dcim.devices.filter(name=task.host.name)

    # Return a failed that there were too many devices returned in the filterset
    if len(device) > 1:
        LOGGER.warning("More than 1 device returned from Nautobot for %s",
                       task.host.name)
        return Result(host=task.host, failed=True)

    # Return a failed when no devices were returned
    if not device:
        LOGGER.warning("No device returned from Nautobot for %s",
                       task.host.name)
        return Result(host=task.host, failed=True)

    results["device"] = dict(device[0])

    # TODO move the logic to pull the interface and potentially IP here
    # interfaces = netbox.dcim.interfaces.filter(device=task.host.name)
    # results["interfaces"] = [ dict(intf) for intf in interfaces ]
    return Result(host=task.host, result=results)
Ejemplo n.º 15
0
def CerberusTest(host, result, schema, allow_unknown=True, **kwargs):
    """
    Function to check results using ``Cerberus`` module schema. Results must be a structured
    data - dictionary, list - strings and other types of data not supported.

    :param host: (obj) Nornir host object
    :param result: ``nornir.core.task.Result`` object
    :param schema: (dictionary) Cerberus schema definition to us for validation
    :param allow_uncknown: (bool) Cerberus allow unknown parameter, default is True
    :param kwargs: (dict) any additional ``**kwargs`` keyword arguments to include in return Result object

    .. warning:: Cerberus library only supports validation of dictionary structures,
        while nested elements could be lists, as a result, ``CerberusTest`` function
        was coded to support validation of dictionary or list of dictionaries results.

    .. note:: ``kwargs`` ``name`` key value formatted using python format function supplying
        dictionary being validated as arguments
    """
    # form ret structure
    ret = test_result_template.copy()
    ret.update(kwargs)

    # run check
    if not HAS_CERBERUS:
        ret.update({"result": "ERROR", "success": False})
        ret[
            "exception"
        ] = "Failed to import Cerberus library, install: pip install cerberus"
        return Result(host=host, **ret)
    validator_engine = Validator()
    validator_engine.allow_unknown = allow_unknown

    # validate dictionary results
    if isinstance(result.result, dict):
        ret = _cerberus_validate_item(validator_engine, result.result, schema, ret)
        return Result(host=host, **ret)
    # validate list of dictionaries results
    elif isinstance(result.result, list):
        validation_results = []
        for item in result.result:
            if not isinstance(item, dict):
                continue
            ret_copy = ret.copy()
            ret_copy = _cerberus_validate_item(validator_engine, item, schema, ret_copy)
            validation_results.append(Result(host=host, **ret_copy))
        return validation_results
    else:
        raise TypeError(
            "nornir-salt:CerberusTest unsupported results type '{}', supported - dictionary, list".format(
                type(result.result)
            )
        )
def validate_ospf_peers(task):
    if task.host.platform == "nxos":
        missing_peers = _validate_ospf_peers_nxos(task)
    else:
        missing_peers = _validate_ospf_peers_eos(task)

    task.results.pop()

    if missing_peers:
        result = f"The following peer(s) are missing or down: {missing_peers}"
        return Result(host=task.host, result=result, failed=True, changed=True)
    result = "All ospf peers validated successfully!"
    return Result(host=task.host, result=result, failed=False, changed=False)
def validate_routes(task):
    if task.host.platform == "nxos":
        missing_routes = _validate_routes_nxos(task)

    else:
        missing_routes = _validate_routes_eos(task)

    if missing_routes:
        result = (
            "The following routes(s) are missing, have incorrect number of next hops, "
            f"or are leaned via the wrong protocol: {missing_routes}")
        return Result(host=task.host, result=result, failed=True, changed=True)
    result = "All routes validated successfully!"
    return Result(host=task.host, result=result, failed=False, changed=False)
Ejemplo n.º 18
0
    def _get_interfaces_ip(task):
        logger.info(f"{task.host}: Getting Interface IP Addresses")

        result = task.run(task=napalm_get,
                          name="Get IP addresses from device",
                          getters=['interfaces_ip'])
        if not result:
            logger.info(f"{task.host}: Failed to get interfaces")
            return Result(host=task.host, failed=True, changed=False)

        ints = result.result['interfaces_ip']

        logger.info(f"{task.host}: Interfaces Retrieved")

        return Result(host=task.host, result=ints, failed=False, changed=False)
Ejemplo n.º 19
0
def vlan_config(task, vlan_id, vlan_name):
    
    hostname = task.host.name
    print(hostname)    
    groupname = task.host.groups[0]
    print(groupname)
    commands = [(f"vlan {vlan_id}"), (f"name {vlan_name}")]
    
    # Netmiko uni test
    uni_test = task.run(
    netmiko_send_command,
    command_string="show vlan",
    use_textfsm=True
    )

    print("-" * 40)
    print(uni_test[0].result)
    print("-" * 40)
    print()
    
    vlan_list = [] 
    for vlan in uni_test[0].result:
        vlan = vlan["vlan_id"]
        vlan_list.append(vlan)
    
    if (f"{vlan_id}") in vlan_list:
        result =  "VLAN 4 already exists, no changes are necessary!"
        changed = False
        failed = False
        return Result(host=task.host, result=result, changed=changed, failed=failed)
    
    changed = True
    # Vlan configuration
    multi_result = task.run(task=netmiko_send_config, config_commands=commands)
    
    if (
        "%Invalid command" in multi_result[0].result
        or "% Invalid input" in multi_result[0].result
    ):
        failed = True
        result_msg = "An invalid configuration command was used."
    else:
        # Note task still could be marked at failed from the "netmiko_send_config"
        # execution i.e. at the MultiResult level.
        failed = False
        result_msg = f"Configured vlan {vlan_id} with name {vlan_name}!"

    return Result(host=task.host, result=result_msg, changed=changed, failed=failed)
Ejemplo n.º 20
0
def napalm_configure(
    task: Task,
    dry_run: Optional[bool] = None,
    filename: Optional[str] = None,
    configuration: Optional[str] = None,
    replace: bool = False,
) -> Result:
    """
    Loads configuration into a network devices using napalm

    Arguments:
        dry_run: Whether to apply changes or not
        filename: filename containing the configuration to load into the device
        configuration: configuration to load into the device
        replace: whether to replace or merge the configuration

    Returns:
        Result object with the following attributes set:
          * changed (``bool``): whether the task is changing the system or not
          * diff (``string``): change in the system
    """
    device = task.host.get_connection("napalm", task.nornir.config)

    if replace:
        device.load_replace_candidate(filename=filename, config=configuration)
    else:
        device.load_merge_candidate(filename=filename, config=configuration)
    diff = device.compare_config()

    dry_run = task.is_dry_run(dry_run)
    if not dry_run and diff:
        device.commit_config()
    else:
        device.discard_config()
    return Result(host=task.host, diff=diff, changed=len(diff) > 0)
Ejemplo n.º 21
0
    def netmiko_run_iperf(self, task: Task) -> Result:
        """
        Runs iperf between a host and several destinations.
        During setup, the destinations have been set up
        to act as servers.

        Note: The destination is not included in the nornir result
        if the iperf test fails. Therefore we cannot know which destination
        was not reachable, so we must patch the destination
        onto the result object to know later
        which host-destination pair actually failed.

        :param task: nornir task for iperf
        :return: All iperf results per host
        """
        destinations_per_host = [
            entry["destination"] for entry in self.nuts_parameters["test_data"]
            if entry["host"] == task.host.name
        ]
        for destination in destinations_per_host:
            escaped_dest = shlex.quote(destination)
            result = task.run(
                task=netmiko_send_command,
                command_string=f"iperf3 -c {escaped_dest} --json",
            )
            result[0].destination = destination  # type: ignore[attr-defined]
        return Result(host=task.host, result=f"iperf executed for {task.host}")
Ejemplo n.º 22
0
def netmiko_send_config(task: Task,
                        config_commands: Optional[List[str]] = None,
                        config_file: Optional[str] = None,
                        **kwargs: Any) -> Result:
    """
    Execute Netmiko send_config_set method (or send_config_from_file)

    Arguments:
        config_commands: Commands to configure on the remote network device.
        config_file: File to read configuration commands from.
        kwargs: Additional arguments to pass to method.

    Returns:
        Result object with the following attributes set:
          * result (``str``): string showing the CLI from the configuration changes.
    """
    net_connect = task.host.get_connection("netmiko", task.nornir.config)
    net_connect.enable()
    if config_commands:
        result = net_connect.send_config_set(config_commands=config_commands,
                                             **kwargs)
    elif config_file:
        result = net_connect.send_config_from_file(config_file=config_file,
                                                   **kwargs)
    else:
        raise ValueError("Must specify either config_commands or config_file")

    return Result(host=task.host, result=result, changed=True)
Ejemplo n.º 23
0
def atc_info(task: Task, atc_method: str, atc_service: str) -> Result:
    """Task to verify if ATC service is available and collect service info.

    Args:
        task (Task): The Nornir task.
        atc_method (str): The HTTP method. Accepted values include [POST, GET]
            for all services, and [DELETE] for AS3.
        atc_service (str): The ATC service.
            Accepted values include [AS3, Device, Telemetry].

    Returns:
        Result: The result.

    Raises:
        Exception: The raised exception when the task had an error.
    """
    client = f5_rest_client(task)
    host = f"{task.host.hostname}:{task.host.port}"

    # Validate ATC service
    if atc_service not in ATC_SERVICE_OPTIONS:
        raise Exception(f"ATC service '{atc_service}' is not valid.")

    # Validate ATC method
    atc_methods = ATC_COMPONENTS[atc_service]["endpoints"]["configure"]["methods"]
    if atc_method not in atc_methods:
        raise Exception(f"ATC method '{atc_method}' is not valid.")

    return Result(
        host=task.host,
        result=client.get(
            f"https://{host}{ATC_COMPONENTS[atc_service]['endpoints']['info']['uri']}"
        ).json(),
    )
Ejemplo n.º 24
0
def task(task, commands, interval=0.01, **kwargs):
    """
    Nornir Task function to send show commands to devices using
    ``nornir_netmiko.tasks.netmiko_send_command`` plugin

    :param kwargs: might contain ``netmiko_kwargs`` argument dictionary
        with parameters for ``nornir_netmiko.tasks.netmiko_send_command``
        method
    :param commands: (list) commands to send to device
    :param interval: (int) interval between sending commands, default 0.01s
    :return result: Nornir result object with task execution results named
        after commands
    """
    # run interval sanity check
    interval = interval if isinstance(interval, (int, float)) else 0.01

    # run commands
    for command in commands:
        task.run(task=netmiko_send_command,
                 command_string=command,
                 name=command,
                 **kwargs.get("netmiko_kwargs", {}))
        time.sleep(interval)

    return Result(host=task.host, skip_results=True)
Ejemplo n.º 25
0
    def render_template_apply(task: Task,
                              template_name: str,
                              template_path: Optional[str] = None) -> Result:

        from jinja2 import Environment, FileSystemLoader, StrictUndefined
        logger.info(f"{task.host}: Rendering Config")

        if not template_path:
            template_path = os.path.join(os.getcwd(),
                                         f'templates/{task.host.platform}')

        env = Environment(
            loader=FileSystemLoader(template_path),
            undefined=StrictUndefined,
            trim_blocks=False,
        )

        config = task.run(task=template_file,
                          name='Render Device Configuration',
                          template=f'{template_name}.j2',
                          jinja_env=env,
                          path=template_path,
                          **task.host)

        result = task.run(task=napalm_configure,
                          dry_run=False,
                          replace=False,
                          configuration=config.result)

        return Result(host=task.host,
                      result=result.result,
                      failed=False,
                      changed=False)
Ejemplo n.º 26
0
def sftp(task, src, dst, action, dry_run=None):
    """
    Transfer files from/to the device using sftp protocol

    Example::

        nornir.run(files.sftp,
                    action="put",
                    src="README.md",
                    dst="/tmp/README.md")

    Arguments:
        dry_run (bool): Whether to apply changes or not
        src (``str``): source file
        dst (``str``): destination
        action (``str``): ``put``, ``get``.

    Returns:
        :obj:`nornir.core.task.Result`:
          * changed (``bool``):
          * files_changed (``list``): list of files that changed
    """
    dry_run = task.is_dry_run(dry_run)
    actions = {"put": put, "get": get}
    client = task.host.get_connection("paramiko")
    scp_client = SCPClient(client.get_transport())
    sftp_client = paramiko.SFTPClient.from_transport(client.get_transport())
    files_changed = actions[action](task, scp_client, sftp_client, src, dst,
                                    dry_run)
    return Result(host=task.host,
                  changed=bool(files_changed),
                  files_changed=files_changed)
Ejemplo n.º 27
0
def identify_breakout_ports(task, interface_list=None):
    '''Nornir task to identify interfaces created by breakout. Such state
    identified by interface name. For NX-OS there will be 2 '/' symbols, for
    VRPv8 there will be ':' symbol.
    Arguments:
        * task - instance or nornir.core.task.Task
        * interface_list (defaults to None) - list of strings, which represents
            switch interface names
    Returns:
        * instance of nornir.core.task.Result
    '''
    if interface_list:
        task.host['interfaces'] = [SwitchInterface(x) for x in interface_list]
    result = 'Interfaces created by breakout:\n'
    if task.host.platform not in ['nxos', 'huawei_vrpv8']:
        raise UnsupportedNOS('task received unsupported NOS - {}'.format(
            task.host.platform))
    for interface in task.host['interfaces']:
        if task.host.platform == 'nxos' and interface.name.count('/') == 2:
            interface.breakout = True
            result += f'\tInterface {interface.name} created by breakout'
        elif task.host.platform == 'huawei_vrpv8' and interface.name.find(
                ':') != -1:
            interface.breakout = True
            result += f'\tInterface {interface.name} created by breakout'
        else:
            interface.breakout = False
    return Result(host=task.host, result=result)
Ejemplo n.º 28
0
def netmiko_send_command(task: Task,
                         command_string: str,
                         use_timing: bool = False,
                         enable: bool = False,
                         **kwargs: Any) -> Result:
    """
    Execute Netmiko send_command method (or send_command_timing)

    Arguments:
        command_string: Command to execute on the remote network device.
        use_timing: Set to True to switch to send_command_timing method.
        enable: Set to True to force Netmiko .enable() call.
        kwargs: Additional arguments to pass to send_command method.

    Returns:
        Result object with the following attributes set:
          * result: Result of the show command (generally a string, but depends on use of TextFSM).
    """
    net_connect = task.host.get_connection("netmiko", task.nornir.config)
    if enable:
        net_connect.enable()
    if use_timing:
        result = net_connect.send_command_timing(command_string, **kwargs)
    else:
        result = net_connect.send_command(command_string, **kwargs)
    return Result(host=task.host, result=result)
Ejemplo n.º 29
0
def pyxl_ez_data(
    task: Task,
    workbook: str,
    sheetname: str,
) -> Result:
    r"""Loads a specific sheet from a workbook(xlsx file).

    Creates a list of dictionaries using the first row as the keys.

    Arguments:
        workbook: Full path to .xlsx file
        sheetname: Worksheet Name

    Examples:
        nr.run(task=pyxl_ez_data, workbookfile="example-wb.xlsx',
               sheetname='ip_data')

    Returns:
        Result object with the following attributes set:
        * result (''list''): list of dictionaries with
        data from the specific worksheet within the workbook.

    Notes:
        read_only: This is hardcoded set to true, as we don't do any writing or
        editing of the file. This also allows the program to explicitly close
        the workbook object and avoid any I/O Operation errors being raised.
    """
    wsheet = open_excel_wb(workbook, sheetname)

    # Assign EMPTY_CELL to a False Bool. We will use this to filter any empty rows
    # Generated in the end. Your spreadsheet should actually not have empty rows.

    empty_cell = False

    data_key = []
    for value in wsheet.iter_rows(values_only=True):
        for key in value:
            # Simple move on if there is no key, we need to stay consistent.
            if not key:
                pass
            else:
                data_key.append(standardize(key))
        break

    rows = []
    for rows_list in wsheet.iter_rows(values_only=True, min_row=2):
        row = []
        for value in rows_list:
            if not value:
                # Adding a placeholder to not lose order when building dict.
                row.append(empty_cell)
            else:
                row.append(check_value(value))
        results = dict(zip(data_key, row))
        rows.append(results)

    # Filter out any potential empty dictionaries due to empty rows/breadcrumbs in XLSX files.
    res = [row for row in rows if not all_false(row)]

    return Result(host=task.host, result=res)
def netmiko_file_transfer(task: Task, source_file: str, dest_file: str,
                          **kwargs: Any) -> Result:
    """
    Execute Netmiko file_transfer method

    Arguments:
        source_file: Source file.
        dest_file: Destination file.
        kwargs: Additional arguments to pass to file_transfer

    Returns:
        Result object with the following attributes set:
          * result (``bool``): file exists and MD5 is valid
          * changed (``bool``): the destination file was changed

    """
    net_connect = task.host.get_connection("netmiko", task.nornir.config)
    kwargs.setdefault("direction", "put")
    scp_result = file_transfer(net_connect,
                               source_file=source_file,
                               dest_file=dest_file,
                               **kwargs)
    if kwargs.get("disable_md5") is True:
        file_valid = scp_result["file_exists"]
    else:
        file_valid = scp_result["file_exists"] and scp_result["file_verified"]
    return Result(host=task.host,
                  result=file_valid,
                  changed=scp_result["file_transferred"])