# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# # Failed Tasks
#
# Sometimes tasks can fail. Let's see how to deal with failed tasks in nornir.
#
# Let's start as usual with the needed boilerplate:

# +
from nornir.core import InitNornir
from nornir.plugins.tasks import networking, text
from nornir.plugins.functions.text import print_result

nr = InitNornir(config_file="config.yaml")
cmh = nr.filter(site="cmh", type="network_device")


# -

# Now, as an example we are going to use a similar task group like the one we used in the previous tutorial:

def basic_configuration(task):
    # Transform inventory data to configuration via a template file
    r = task.run(task=text.template_file,
                 name="Base Configuration",
                 template="base.j2",
                 path=f"templates/junos")

    # Save the compiled configuration into a host variable
    task.host["config"] = r.result

    # Deploy that configuration to the device using NAPALM
    task.run(task=networking.napalm_configure,
             name="Loading Configuration on the device",
             replace=False,
             configuration=task.host["config"])


# Note that the path is hardcoded to templates/junos, this should cause an error when trying to apply the configuration to the EOS devices. Let's see what happens:

result = cmh.run(task=basic_configuration)

# Let's inspect the object:

result.failed

result.failed_hosts

result['spine00.cmh'][1].exception

# As you can see, the result object is aware something went wrong and you can inspect the errors if you so desire.
#
# You can also using the `print_result` function on it:

print_result(result)

# There is also a method that will raise an exception if the task had an error:

from nornir.core.exceptions import NornirExecutionError
try:
    result.raise_on_error()
except NornirExecutionError:
    print("ERROR!!!")

# ## Skipped hosts
#
# Nornir will keep track of hosts that failed and won't run future tasks on them:

# +
from nornir.core.task import Result

def hi(task):
    return Result(host=task.host, result=f"{task.host.name}: Hi, I am still here!")
    
result = cmh.run(task=hi)
# -

print_result(result)

# You can force the execution of tasks on failed hosts by passing the arguments `run_on_failed=True`:

result = cmh.run(task=hi, on_failed=True)
print_result(result)

# You can also exclude the hosts that are "good" if you want to with the `run_on_good` flag:

result = cmh.run(task=hi, on_failed=True, on_good=False)
print_result(result)

# To achieve this `nornir` keeps a list failed hosts in it's shared [data](../../ref/api/nornir.rst#nornir.core.Data) object:

nr.data.failed_hosts

# If you want to mark some hosts as succeeded and make them back eligible for future tasks you can do it individually per host with the function [recover_host](../../ref/api/nornir.rst#nornir.core.Data.recover_host) or reset the list completely with [reset_failed_hosts](../../ref/api/nornir.rst#nornir.core.Data.reset_failed_hosts):

nr.data.reset_failed_hosts()
nr.data.failed_hosts

# ## Raise on error automatically
#
# Alternatively, you can configure nornir to raise the exception automatically in case of error with the `raise_on_error` configuration option:

nr = InitNornir(config_file="config.yaml", raise_on_error=True)
cmh = nr.filter(site="cmh", type="network_device")
try:
    cmh.run(task=basic_configuration)
except NornirExecutionError:
    print("ERROR!!!")

# ## Workflows

# The default workflow should work for most use cases as hosts with errors are skipped and the `print_result` should give enough information to understand what's going on. For more complex workflows this framework should give you enough room to easily implement them regardless of the complexity.

StarcoderdataJupyterScriptsDedupFiltered