diff --git a/.gitignore b/.gitignore index f5259f1..0f43244 100644 --- a/.gitignore +++ b/.gitignore @@ -73,3 +73,7 @@ dmypy.json # macos stuff .DS_Store */.DS_Store + +# nornir (or any other) log files from testing +.log +*/.log diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..3f05804 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,3 @@ +# Contributing + +Contributions are not expected, but are very welcome! Feel free to open PRs or Issues as needed. Any contributions would need to at a minimum successfully pass the GitHub Actions commit build (which basically just runs tox). diff --git a/Makefile b/Makefile index 6391d9c..989822e 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -test_unit: +tests: python -m pytest \ --cov=nornsible \ --cov-report html \ diff --git a/README.md b/README.md index dfe18d3..bb5b653 100644 --- a/README.md +++ b/README.md @@ -8,3 +8,131 @@ nornsible ======= Wrap Nornir with Ansible-like host/group limits and tagging! + +The idea behind nornsible is to allow for Nornir scripts to be written to operate on an entire environment, and then limited to a subset of host(s) based on simple command line arguments. Of course you can simply do this yourself, but why not let nornsible handle it for you! + +Nornsible provides the ability to -- via command line arguments -- filter Nornir inventories by hostname or group name, or both. There is also a handy flag to set the number of workers; quite useful for setting workers to 1 for troubleshooting purposes. + +Lastly nornsible supports the concept of tags. Tags correspond to the name of *custom* tasks and operate very much like tags in Ansible. Provide a list of tags to execute, and Nornsible will ensure that Nornir only runs those tasks. Provide a list of tags to skip, and Nornsible will ensure that Nornir only runs those not in that list. Easy peasy. + + +# How does nornsible work? + +Nornsible accepts an instantiated Nornir object as an argument and returns a slightly Nornir object. Nornsible sets the desired number of workers if applicable, and addts an attribute for "run_tags" and "skip_tags" based on your command line input. + +To take advantage of the tags feautre Nornsible provides a decorator that you can use to decorate your custom tasks. This decorator inspects the task being ran and checks the task name against the lists of run and skip tags. If the task is allowed, Nornsible simply allows the task to run as per normal, if it is *not* allowed, Nornsible will print a pretty message and move on. + + +# Caveats + +Nornsible breaks some things! Most notably it breaks "normal" Nornir filtering *after* the Nornir object is "nornsible-ified". This can probably be fixed but at the moment it doesn't seem like that big a deal, so I'm not bothering! + +If you want to do "normal" Nornir filtering -- do this *before* passing the nornir object to Nornsible. + +Nornsible, at the moment, can only wrap custom tasks. This can probably be imporved upon as well, but at the moment the decorator wrapping custom tasks solution seems to work pretty well. + + +# Installation + +Installation via pip: + +``` +pip install nornsible +``` + +To install from this repository: + +``` +pip install git+https://github.com/carlmontanari/nornsible +``` + +To install from source: + +``` +git clone https://github.com/carlmontanari/nornsible +cd nornsible +python setup.py install +``` + + +# Usage + +Import stuff: + +``` +from nornsible import InitNornsible, nornsible_task +``` + +Decorate custom tasks with `nornsible_task` if desired: + +``` +@nornsible_task +def my_custom_task(task): +``` + +Create your Nornir object and then pass it through InitNornsible: + +``` +nr = InitNornir(config_file="config.yaml") +nr = Init_Nornsible(nr) +``` + +Run a custom task wrapped by `nornsible_task`: + +``` +nr.run(task=my_custom_task) +``` + +Run your script with any of the following command line switches: + +| Purpose | Short Flag | Long Flag | Allowed Options +| -----------------|---------------|------------|-------------------| +| set num_workers | -w | --workers | integer | +| limit host(s) | -l | --limit | comma sep string | +| limit group(s) | -g | --groups | comma sep string | +| run tag(s) | -t | --tags | comma sep string | +| skip tag(s) | -s | --skip | comma sep string | + +To set number of workers to 1 for troubleshooting purposes: + +``` +python my_nornir_script.py -w 1 +``` + +To limit to the "sea" group (from your Nornir inventory): + +``` +python my_nornir_script.py -g sea +``` + +To run only the tasks named "create_configs" and "deploy_configs" (assuming you've wrapped all of your tasks with `nornsible_task`!): + +``` +python my_nornir_script.py -t create_configs,deploy_configs +``` + +To run only the tasks named "create_configs" and "deploy_configs" against the "sea-eos-1" host: + +``` +python my_nornir_script.py -t create_configs,deploy_configs -l sea-eos-1 +``` + + +# FAQ + +TBA, probably things though! + +# Linting and Testing + +## Linting + +This project uses [black](https://github.com/psf/black) for auto-formatting. In addition to black, tox will execute [pylama](https://github.com/klen/pylama), and [pydocstyle](https://github.com/PyCQA/pydocstyle) for linting purposes. I've also added docstring linting with [darglint](https://github.com/terrencepreilly/darglint) which has been quite handy! + +## Testing + +I broke testing into two main categories -- unit and integration. Unit is what you would expect -- unit testing the code. Integration testing is for things that test more than one "unit" (generally function) at a time. + + +# To Do + +- Add handling for "not" in host/group limit; i.e.: "-t !localhost" to run against all hosts *not* localhost. diff --git a/docs/nornsible/index.html b/docs/nornsible/index.html index 06121e3..dd32831 100644 --- a/docs/nornsible/index.html +++ b/docs/nornsible/index.html @@ -28,16 +28,24 @@

Module nornsible

from logging import NullHandler from nornsible.nornsible import ( - Init_Nornsible, + InitNornsible, parse_cli_args, - process_tags, + nornsible_task, patch_config, patch_inventory, + nornsible_task_message, ) __version__ = "2019.09.16" -__all__ = ("Init_Nornsible", "parse_cli_args", "process_tags", "patch_config", "patch_inventory") +__all__ = ( + "InitNornsible", + "parse_cli_args", + "nornsible_task", + "patch_config", + "patch_inventory", + "nornsible_task_message", +) # Setup logger @@ -59,8 +67,8 @@

Sub-modules

Functions

-
-def Init_Nornsible(nr) +
+def InitNornsible(nr)

Patch nornir object based on cli arguments

@@ -82,7 +90,7 @@

Raises

Source code -
def Init_Nornsible(nr):
+
def InitNornsible(nr):
     """
     Patch nornir object based on cli arguments
 
@@ -109,6 +117,105 @@ 

Raises

return nr
+
+def nornsible_task(wrapped_func) +
+
+

Decorate an "operation" – execute or skip the operation based on tags

+

Args

+
+
wrapped_func
+
function to wrap in tag processor
+
+

Returns

+
+
tag_wrapper
+
wrapped function
+
+

Raises

+
+
N/A +# noqa
+
 
+
+
+Source code +
def nornsible_task(wrapped_func):
+    """
+    Decorate an "operation" -- execute or skip the operation based on tags
+
+    Args:
+        wrapped_func: function to wrap in tag processor
+
+    Returns:
+        tag_wrapper: wrapped function
+
+    Raises:
+        N/A  # noqa
+
+    """
+
+    def tag_wrapper(task, *args, **kwargs):
+        if {wrapped_func.__name__}.intersection(task.nornir.skip_tags):
+            msg = f"---- {task.host} skipping task {wrapped_func.__name__} "
+            nornsible_task_message(msg)
+            return Result(host=task.host, result="Task skipped!", failed=False, changed=False)
+        if not task.nornir.run_tags:
+            return wrapped_func(task, *args, **kwargs)
+        if {wrapped_func.__name__}.intersection(task.nornir.run_tags):
+            return wrapped_func(task, *args, **kwargs)
+        msg = f"---- {task.host} skipping task {wrapped_func.__name__} "
+        nornsible_task_message(msg)
+        return Result(host=task.host, result="Task skipped!", failed=False, changed=False)
+
+    tag_wrapper.__name__ = wrapped_func.__name__
+    return tag_wrapper
+
+
+
+def nornsible_task_message(msg) +
+
+

Handle printing pretty messages for nornsible_task decorator

+

Args

+
+
msg
+
message to beautifully print to stdout
+
+

Returns

+
+
N/A
+
 
+
+

Raises

+
+
N/A +# noqa
+
 
+
+
+Source code +
def nornsible_task_message(msg):
+    """
+    Handle printing pretty messages for nornsible_task decorator
+
+    Args:
+        msg: message to beautifully print to stdout
+
+    Returns:
+         N/A
+
+    Raises:
+        N/A  # noqa
+
+    """
+    LOCK.acquire()
+    try:
+        print(f"{Style.BRIGHT}{Back.CYAN}{Fore.WHITE}{msg}{'-' * (80 - len(msg))}")
+    finally:
+        LOCK.release()
+
+
def parse_cli_args(args)
@@ -295,61 +402,6 @@

Raises

return inv
-
-def process_tags(wrapped_func) -
-
-

Decorate an "operation" – execute or skip the operation based on tags

-

Args

-
-
wrapped_func
-
function to wrap in tag processor
-
-

Returns

-
-
tag_wrapper
-
wrapped function
-
-

Raises

-
-
N/A -# noqa
-
 
-
-
-Source code -
def process_tags(wrapped_func):
-    """
-    Decorate an "operation" -- execute or skip the operation based on tags
-
-    Args:
-        wrapped_func: function to wrap in tag processor
-
-    Returns:
-        tag_wrapper: wrapped function
-
-    Raises:
-        N/A  # noqa
-
-    """
-
-    def tag_wrapper(task, *args, **kwargs):
-        if set([wrapped_func.__name__]).intersection(task.nornir.skip_tags):
-            msg = f"---- {task.host} skipping task {wrapped_func.__name__} "
-            process_tags_messages(msg)
-            return Result(host=task.host, result="Task skipped!", failed=False, changed=False)
-        if not task.nornir.run_tags:
-            return wrapped_func(task, *args, **kwargs)
-        if set([wrapped_func.__name__]).intersection(task.nornir.run_tags):
-            return wrapped_func(task, *args, **kwargs)
-        msg = f"---- {task.host} skipping task {wrapped_func.__name__} "
-        process_tags_messages(msg)
-        return Result(host=task.host, result="Task skipped!", failed=False, changed=False)
-
-    tag_wrapper.__name__ = wrapped_func.__name__
-    return tag_wrapper
-
-
@@ -368,11 +420,12 @@

Index

  • Functions

  • diff --git a/docs/nornsible/nornsible.html b/docs/nornsible/nornsible.html index 63ea105..da87a2b 100644 --- a/docs/nornsible/nornsible.html +++ b/docs/nornsible/nornsible.html @@ -23,16 +23,13 @@

    Module nornsible.nornsible

    Source code
    import argparse
    -import logging
     import sys
     import threading
     
    -from colorama import Fore, Style, init
    +from colorama import Back, Fore, init, Style
     from nornir.core.task import Result
     
     
    -session_log = logging.getLogger(__name__)
    -
     init(autoreset=True, strip=False)
     LOCK = threading.Lock()
     
    @@ -150,9 +147,9 @@ 

    Module nornsible.nornsible

    return conf -def process_tags_messages(msg): +def nornsible_task_message(msg): """ - Handle printing pretty messages for process_tags decorator + Handle printing pretty messages for nornsible_task decorator Args: msg: message to beautifully print to stdout @@ -166,12 +163,12 @@

    Module nornsible.nornsible

    """ LOCK.acquire() try: - print("{}{}{}{}".format(Style.BRIGHT, Fore.CYAN, msg, "-" * (80 - len(msg)))) + print(f"{Style.BRIGHT}{Back.CYAN}{Fore.WHITE}{msg}{'-' * (80 - len(msg))}") finally: LOCK.release() -def process_tags(wrapped_func): +def nornsible_task(wrapped_func): """ Decorate an "operation" -- execute or skip the operation based on tags @@ -187,23 +184,23 @@

    Module nornsible.nornsible

    """ def tag_wrapper(task, *args, **kwargs): - if set([wrapped_func.__name__]).intersection(task.nornir.skip_tags): + if {wrapped_func.__name__}.intersection(task.nornir.skip_tags): msg = f"---- {task.host} skipping task {wrapped_func.__name__} " - process_tags_messages(msg) + nornsible_task_message(msg) return Result(host=task.host, result="Task skipped!", failed=False, changed=False) if not task.nornir.run_tags: return wrapped_func(task, *args, **kwargs) - if set([wrapped_func.__name__]).intersection(task.nornir.run_tags): + if {wrapped_func.__name__}.intersection(task.nornir.run_tags): return wrapped_func(task, *args, **kwargs) msg = f"---- {task.host} skipping task {wrapped_func.__name__} " - process_tags_messages(msg) + nornsible_task_message(msg) return Result(host=task.host, result="Task skipped!", failed=False, changed=False) tag_wrapper.__name__ = wrapped_func.__name__ return tag_wrapper -def Init_Nornsible(nr): +def InitNornsible(nr): """ Patch nornir object based on cli arguments @@ -237,8 +234,8 @@

    Module nornsible.nornsible

    Functions

    -
    -def Init_Nornsible(nr) +
    +def InitNornsible(nr)

    Patch nornir object based on cli arguments

    @@ -260,7 +257,7 @@

    Raises

    Source code -
    def Init_Nornsible(nr):
    +
    def InitNornsible(nr):
         """
         Patch nornir object based on cli arguments
     
    @@ -287,6 +284,105 @@ 

    Raises

    return nr
    +
    +def nornsible_task(wrapped_func) +
    +
    +

    Decorate an "operation" – execute or skip the operation based on tags

    +

    Args

    +
    +
    wrapped_func
    +
    function to wrap in tag processor
    +
    +

    Returns

    +
    +
    tag_wrapper
    +
    wrapped function
    +
    +

    Raises

    +
    +
    N/A +# noqa
    +
     
    +
    +
    +Source code +
    def nornsible_task(wrapped_func):
    +    """
    +    Decorate an "operation" -- execute or skip the operation based on tags
    +
    +    Args:
    +        wrapped_func: function to wrap in tag processor
    +
    +    Returns:
    +        tag_wrapper: wrapped function
    +
    +    Raises:
    +        N/A  # noqa
    +
    +    """
    +
    +    def tag_wrapper(task, *args, **kwargs):
    +        if {wrapped_func.__name__}.intersection(task.nornir.skip_tags):
    +            msg = f"---- {task.host} skipping task {wrapped_func.__name__} "
    +            nornsible_task_message(msg)
    +            return Result(host=task.host, result="Task skipped!", failed=False, changed=False)
    +        if not task.nornir.run_tags:
    +            return wrapped_func(task, *args, **kwargs)
    +        if {wrapped_func.__name__}.intersection(task.nornir.run_tags):
    +            return wrapped_func(task, *args, **kwargs)
    +        msg = f"---- {task.host} skipping task {wrapped_func.__name__} "
    +        nornsible_task_message(msg)
    +        return Result(host=task.host, result="Task skipped!", failed=False, changed=False)
    +
    +    tag_wrapper.__name__ = wrapped_func.__name__
    +    return tag_wrapper
    +
    +
    +
    +def nornsible_task_message(msg) +
    +
    +

    Handle printing pretty messages for nornsible_task decorator

    +

    Args

    +
    +
    msg
    +
    message to beautifully print to stdout
    +
    +

    Returns

    +
    +
    N/A
    +
     
    +
    +

    Raises

    +
    +
    N/A +# noqa
    +
     
    +
    +
    +Source code +
    def nornsible_task_message(msg):
    +    """
    +    Handle printing pretty messages for nornsible_task decorator
    +
    +    Args:
    +        msg: message to beautifully print to stdout
    +
    +    Returns:
    +         N/A
    +
    +    Raises:
    +        N/A  # noqa
    +
    +    """
    +    LOCK.acquire()
    +    try:
    +        print(f"{Style.BRIGHT}{Back.CYAN}{Fore.WHITE}{msg}{'-' * (80 - len(msg))}")
    +    finally:
    +        LOCK.release()
    +
    +
    def parse_cli_args(args)
    @@ -473,105 +569,6 @@

    Raises

    return inv
    -
    -def process_tags(wrapped_func) -
    -
    -

    Decorate an "operation" – execute or skip the operation based on tags

    -

    Args

    -
    -
    wrapped_func
    -
    function to wrap in tag processor
    -
    -

    Returns

    -
    -
    tag_wrapper
    -
    wrapped function
    -
    -

    Raises

    -
    -
    N/A -# noqa
    -
     
    -
    -
    -Source code -
    def process_tags(wrapped_func):
    -    """
    -    Decorate an "operation" -- execute or skip the operation based on tags
    -
    -    Args:
    -        wrapped_func: function to wrap in tag processor
    -
    -    Returns:
    -        tag_wrapper: wrapped function
    -
    -    Raises:
    -        N/A  # noqa
    -
    -    """
    -
    -    def tag_wrapper(task, *args, **kwargs):
    -        if set([wrapped_func.__name__]).intersection(task.nornir.skip_tags):
    -            msg = f"---- {task.host} skipping task {wrapped_func.__name__} "
    -            process_tags_messages(msg)
    -            return Result(host=task.host, result="Task skipped!", failed=False, changed=False)
    -        if not task.nornir.run_tags:
    -            return wrapped_func(task, *args, **kwargs)
    -        if set([wrapped_func.__name__]).intersection(task.nornir.run_tags):
    -            return wrapped_func(task, *args, **kwargs)
    -        msg = f"---- {task.host} skipping task {wrapped_func.__name__} "
    -        process_tags_messages(msg)
    -        return Result(host=task.host, result="Task skipped!", failed=False, changed=False)
    -
    -    tag_wrapper.__name__ = wrapped_func.__name__
    -    return tag_wrapper
    -
    -
    -
    -def process_tags_messages(msg) -
    -
    -

    Handle printing pretty messages for process_tags decorator

    -

    Args

    -
    -
    msg
    -
    message to beautifully print to stdout
    -
    -

    Returns

    -
    -
    N/A
    -
     
    -
    -

    Raises

    -
    -
    N/A -# noqa
    -
     
    -
    -
    -Source code -
    def process_tags_messages(msg):
    -    """
    -    Handle printing pretty messages for process_tags decorator
    -
    -    Args:
    -        msg: message to beautifully print to stdout
    -
    -    Returns:
    -         N/A
    -
    -    Raises:
    -        N/A  # noqa
    -
    -    """
    -    LOCK.acquire()
    -    try:
    -        print("{}{}{}{}".format(Style.BRIGHT, Fore.CYAN, msg, "-" * (80 - len(msg))))
    -    finally:
    -        LOCK.release()
    -
    -
    @@ -590,12 +587,12 @@

    Index

  • Functions

  • diff --git a/examples/config.yaml b/examples/config.yaml new file mode 100644 index 0000000..8e9b42a --- /dev/null +++ b/examples/config.yaml @@ -0,0 +1,8 @@ +inventory: + plugin: nornir.plugins.inventory.simple.SimpleInventory + options: + host_file: "hosts.yaml" + group_file: "groups.yaml" + +logging: + enabled: False diff --git a/examples/groups.yaml b/examples/groups.yaml new file mode 100644 index 0000000..7783210 --- /dev/null +++ b/examples/groups.yaml @@ -0,0 +1,4 @@ +--- +sea: {} +nxos: {} +eos: {} diff --git a/examples/hosts.yaml b/examples/hosts.yaml new file mode 100644 index 0000000..f4bd04d --- /dev/null +++ b/examples/hosts.yaml @@ -0,0 +1,15 @@ +--- +sea-eos-1: + hostname: 127.0.0.1 + groups: + - sea + - eos + +sea-nxos-1: + hostname: 127.0.0.1 + groups: + - sea + - nxos + +localhost: + hostname: 127.0.0.1 diff --git a/examples/try_me.md b/examples/try_me.md new file mode 100644 index 0000000..d14d611 --- /dev/null +++ b/examples/try_me.md @@ -0,0 +1,82 @@ +# Nornsible Example + +This directory contains a hosts, groups, and config file for Nornir. All of the hosts are simply set to use 127.0.0.1 as a hostname so you should be able to test nornsible out using these files quite easily! Ensure you've installed nornsible and the requirements.txt file before proceeding. + + +## Executing Normally + +Without nornsible the two custom tasks execute against all three hosts (sea-eos-1, sea-nxos-1, and localhost) as you'd expect, nice and easy Nornir stuff. + + +## Limit Workers + +``` +$ python try_me.py -w 1 +1 +[SNIP] +``` + + +## Limit Host(s) + +``` +$ python try_me.py -l sea-eos-1 +my_custom_task_1**************************************************************** +* sea-eos-1 ** changed : False ************************************************* +vvvv my_custom_task_1 ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO +---- command ** changed : False ------------------------------------------------ INFO +hello, world! + +hello, world! + +^^^^ END my_custom_task_1 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +my_custom_task_10*************************************************************** +* sea-eos-1 ** changed : False ************************************************* +vvvv my_custom_task_10 ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO +---- command ** changed : False ------------------------------------------------ INFO +hello, from task 10! + +hello, from task 10! + +^^^^ END my_custom_task_10 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +``` + +## Limit host(s) and task(s) + +``` +$ python try_me.py -l sea-eos-1 -t custom_task_1 +---- sea-eos-1 skipping task my_custom_task_1 ---------------------------------- +my_custom_task_1**************************************************************** +* sea-eos-1 ** changed : False ************************************************* +vvvv my_custom_task_1 ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO +Task skipped! +^^^^ END my_custom_task_1 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +---- sea-eos-1 skipping task my_custom_task_10 --------------------------------- +my_custom_task_10*************************************************************** +* sea-eos-1 ** changed : False ************************************************* +vvvv my_custom_task_10 ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO +Task skipped! +^^^^ END my_custom_task_10 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +``` + +## Limit host(s) and skip task(s) + +``` +$ python try_me.py -l sea-eos-1 -s my_custom_task_1 +20 +---- sea-eos-1 skipping task my_custom_task_1 ---------------------------------- +my_custom_task_1**************************************************************** +* sea-eos-1 ** changed : False ************************************************* +vvvv my_custom_task_1 ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO +Task skipped! +^^^^ END my_custom_task_1 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +my_custom_task_10*************************************************************** +* sea-eos-1 ** changed : False ************************************************* +vvvv my_custom_task_10 ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO +---- command ** changed : False ------------------------------------------------ INFO +hello, from task 10! + +hello, from task 10! + +^^^^ END my_custom_task_10 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +``` diff --git a/examples/try_me.py b/examples/try_me.py new file mode 100644 index 0000000..a40c1ff --- /dev/null +++ b/examples/try_me.py @@ -0,0 +1,34 @@ +from nornir import InitNornir +from nornir.plugins.functions.text import print_result +from nornir.plugins.tasks import commands + +from nornsible import InitNornsible, nornsible_task + + +@nornsible_task +def my_custom_task_1(task): + task.run(task=commands.command, command="echo 'hello, world!'") + + +""" +MOAR CUSTOM TASKS MAYBE?! +""" + + +@nornsible_task +def my_custom_task_10(task): + task.run(task=commands.command, command="echo 'hello, from task 10!'") + + +def main(): + nr = InitNornir(config_file="config.yaml") + nr = InitNornsible(nr) + print(nr.config.core.num_workers) + agg_result = nr.run(task=my_custom_task_1) + print_result(agg_result) + agg_result = nr.run(task=my_custom_task_10) + print_result(agg_result) + + +if __name__ == "__main__": + main() diff --git a/nornir.log b/nornir.log index ed37275..9654be4 100644 --- a/nornir.log +++ b/nornir.log @@ -1,198 +1,45 @@ -2019-09-16 19:37:02,198 - nornir.core - INFO - run() - Running task 'command' with args {'command': "echo 'Hello World!'"} on 1 hosts -2019-09-16 19:37:08,378 - nornir.core - INFO - run() - Running task 'command' with args {'command': "echo 'Hello World!'"} on 1 hosts -2019-09-16 19:37:14,004 - nornir.core - INFO - run() - Running task 'command' with args {'command': "echo 'Hello World!'"} on 1 hosts -2019-09-16 19:37:58,361 - nornir.core - INFO - run() - Running task 'command' with args {'command': "echo 'Hello World!'"} on 1 hosts -2019-09-16 19:39:03,808 - nornir.core - INFO - run() - Running task 'command' with args {'command': "echo 'Hello World!'"} on 3 hosts -2019-09-16 19:39:08,578 - nornir.core - INFO - run() - Running task 'command' with args {'command': "echo 'Hello World!'"} on 3 hosts -2019-09-16 19:40:13,277 - nornir.core - INFO - run() - Running task 'command' with args {'command': "echo 'Hello World!'"} on 1 hosts -2019-09-16 19:40:41,964 - nornir.core - INFO - run() - Running task 'command' with args {'command': "echo 'Hello World!'"} on 1 hosts -2019-09-16 19:40:47,755 - nornir.core - INFO - run() - Running task 'command' with args {'command': "echo 'Hello World!'"} on 1 hosts -2019-09-16 19:41:10,006 - nornir.core - INFO - run() - Running task 'command' with args {'command': "echo 'Hello World!'"} on 1 hosts -2019-09-16 19:41:26,100 - nornir.core - INFO - run() - Running task 'command' with args {'command': "echo 'Hello World!'"} on 1 hosts -2019-09-16 19:41:44,780 - nornir.core - INFO - run() - Running task 'command' with args {'command': "echo 'Hello World!'"} on 1 hosts -2019-09-16 19:42:04,016 - nornir.core - INFO - run() - Running task 'command' with args {'command': "echo 'Hello World!'"} on 1 hosts -2019-09-16 19:43:02,044 - nornir.core - INFO - run() - Running task 'command' with args {'command': "echo 'Hello World!'"} on 1 hosts -2019-09-16 19:43:05,076 - nornir.core - INFO - run() - Running task 'command' with args {'command': "echo 'Hello World!'"} on 1 hosts -2019-09-16 19:43:45,462 - nornir.core - INFO - run() - Running task 'test_task' with args {'command': "echo 'Hello World!'", 'name': 'test_task'} on 1 hosts -2019-09-16 19:43:58,826 - nornir.core - INFO - run() - Running task 'test_task' with args {'command': "echo 'Hello World!'", 'name': 'test_task'} on 1 hosts -2019-09-16 19:44:01,400 - nornir.core - INFO - run() - Running task 'test_task' with args {'command': "echo 'Hello World!'", 'name': 'test_task'} on 1 hosts -2019-09-16 19:44:29,006 - nornir.core - INFO - run() - Running task 'command' with args {'command': "echo 'Hello World!'"} on 1 hosts -2019-09-16 19:45:01,330 - nornir.core - INFO - run() - Running task 'command' with args {'command': "echo 'Hello World!'"} on 1 hosts -2019-09-16 19:45:22,916 - nornir.core - INFO - run() - Running task 'command' with args {'command': "echo 'Hello World!'"} on 1 hosts -2019-09-16 19:45:46,696 - nornir.core - INFO - run() - Running task 'command' with args {'command': "echo 'Hello World!'"} on 1 hosts -2019-09-16 19:46:10,498 - nornir.core - INFO - run() - Running task 'command' with args {'command': "echo 'Hello World!'"} on 1 hosts -2019-09-16 19:46:26,283 - nornir.core - INFO - run() - Running task 'command' with args {'command': "echo 'Hello World!'"} on 1 hosts -2019-09-16 19:46:43,474 - nornir.core - INFO - run() - Running task 'command' with args {'command': "echo 'Hello World!'"} on 1 hosts -2019-09-16 19:47:10,997 - nornir.core - INFO - run() - Running task 'command' with args {'command': "echo 'Hello World!'"} on 1 hosts -2019-09-16 19:47:22,262 - nornir.core - INFO - run() - Running task 'something' with args {'command': "echo 'Hello World!'", 'name': 'something'} on 1 hosts -2019-09-16 19:47:30,688 - nornir.core - INFO - run() - Running task 'test_task' with args {'command': "echo 'Hello World!'", 'name': 'test_task'} on 1 hosts -2019-09-16 19:47:40,781 - nornir.core - INFO - run() - Running task 'test_task' with args {'command': "echo 'Hello World!'", 'name': 'test_task'} on 1 hosts -2019-09-16 19:47:53,470 - nornir.core - INFO - run() - Running task 'test_task' with args {'command': "echo 'Hello World!'", 'name': 'test_task'} on 1 hosts -2019-09-16 19:51:00,087 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 19:51:25,424 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 19:51:47,053 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 19:53:20,744 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 19:53:20,854 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 19:53:37,383 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 19:53:37,491 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 19:54:34,558 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 19:54:34,668 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 19:58:04,375 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 19:58:04,480 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 19:58:27,559 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 19:58:27,665 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 19:59:48,096 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 3 hosts -2019-09-16 19:59:48,200 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 3 hosts -2019-09-16 20:00:30,289 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:00:30,398 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 20:00:48,542 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:00:48,646 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 20:01:23,371 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:01:23,475 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 20:02:16,208 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:02:28,262 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:03:49,555 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:03:49,664 - nornir.core - INFO - run() - Running task 'another_custom_task_example' with args {} on 1 hosts -2019-09-16 20:09:01,861 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:09:01,967 - nornir.core - INFO - run() - Running task 'another_custom_task_example' with args {} on 1 hosts -2019-09-16 20:09:17,552 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:09:17,790 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:09:17,896 - nornir.core - INFO - run() - Running task 'another_custom_task_example' with args {} on 1 hosts -2019-09-16 20:10:10,489 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:10:10,733 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:10:10,840 - nornir.core - INFO - run() - Running task 'another_custom_task_example' with args {} on 1 hosts -2019-09-16 20:13:15,262 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:13:54,479 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:14:26,714 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:15:22,175 - nornir.core.task - ERROR - start() - Host 'localhost': task 'custom_task_example' failed with traceback: -Traceback (most recent call last): - File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/nornir/core/task.py", line 67, in start - r = self.task(self, **self.params) - File "/Users/carl/Dev/GitHub/nornsible/nornsible/nornsible.py", line 149, in tag_wrapper - if set([wrapped_func.__name__]).intersection(task.nornir.skip_tags): - File "/Users/carl/Dev/GitHub/nornsible/nornsible/nornsible.py", line 149, in tag_wrapper - if set([wrapped_func.__name__]).intersection(task.nornir.skip_tags): - File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/bdb.py", line 88, in trace_dispatch - return self.dispatch_line(frame) - File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/bdb.py", line 113, in dispatch_line - if self.quitting: raise BdbQuit -bdb.BdbQuit - -2019-09-16 20:15:32,325 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:15:39,661 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:15:39,774 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:15:39,882 - nornir.core - INFO - run() - Running task 'another_custom_task_example' with args {} on 1 hosts -2019-09-16 20:16:33,257 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:16:41,494 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:16:41,605 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:16:41,713 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 20:17:17,249 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:17:17,360 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:17:17,468 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 20:17:59,969 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:18:00,082 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:18:00,191 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 20:18:20,879 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:18:20,984 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 20:18:54,682 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:18:54,788 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 20:19:18,047 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:19:18,154 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 20:19:53,243 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:19:53,348 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 20:20:15,934 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:20:16,041 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 20:20:24,729 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:20:24,843 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:20:24,947 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 20:20:41,693 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:20:41,805 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:20:41,914 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 20:20:44,591 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:20:44,707 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:20:44,812 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 20:22:23,439 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:22:23,552 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:22:23,660 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 20:22:23,775 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:22:23,878 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 20:22:28,717 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:22:28,829 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:22:28,937 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 20:22:29,051 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:22:29,156 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 20:22:31,168 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:22:31,280 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:22:31,390 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 20:22:31,504 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:22:31,608 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 20:23:31,157 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:23:31,275 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:23:31,386 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 20:23:31,499 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:23:31,605 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 20:23:33,578 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:23:33,698 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:23:33,804 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 20:23:33,923 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:23:34,028 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 20:24:43,184 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:24:43,299 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:24:43,409 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 20:24:43,526 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:24:43,631 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 20:24:45,649 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:24:45,763 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:24:45,869 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 20:24:45,980 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:24:46,086 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 20:28:28,234 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:28:28,347 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:28:28,455 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 20:28:28,568 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:28:28,675 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 20:28:30,698 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:28:30,812 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:28:30,918 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 20:28:31,036 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:28:31,143 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 20:37:06,064 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:37:06,176 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:37:06,286 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 20:37:06,402 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:37:06,508 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 20:37:08,614 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:37:08,730 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:37:08,835 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 20:37:08,953 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:37:09,063 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 20:38:08,719 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:38:08,833 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:38:08,940 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 20:38:09,053 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:38:09,158 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 20:38:11,247 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:38:11,364 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:38:11,474 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 20:38:11,586 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:38:11,696 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 20:38:42,694 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:38:42,812 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:38:42,922 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 20:38:43,040 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:38:43,150 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 20:38:45,435 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:38:45,547 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:38:45,651 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 20:38:45,767 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:38:45,877 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 20:38:56,192 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:38:56,311 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:38:56,418 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 20:38:56,534 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:38:56,640 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 20:38:58,677 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:38:58,796 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:38:58,905 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts -2019-09-16 20:38:59,018 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts -2019-09-16 20:38:59,127 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts +2019-09-17 18:37:46,532 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts +2019-09-17 18:37:46,648 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts +2019-09-17 18:37:46,757 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts +2019-09-17 18:37:46,867 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts +2019-09-17 18:37:46,977 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts +2019-09-17 18:48:13,516 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts +2019-09-17 18:48:13,630 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts +2019-09-17 18:48:13,737 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts +2019-09-17 18:48:13,847 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts +2019-09-17 18:48:13,955 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts +2019-09-17 18:48:35,818 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts +2019-09-17 18:48:35,933 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts +2019-09-17 18:48:36,042 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts +2019-09-17 18:48:36,156 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts +2019-09-17 18:48:36,265 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts +2019-09-17 19:22:28,266 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts +2019-09-17 19:22:28,379 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts +2019-09-17 19:22:28,487 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts +2019-09-17 19:22:28,601 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts +2019-09-17 19:22:28,709 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts +2019-09-17 19:22:31,670 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts +2019-09-17 19:22:31,789 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts +2019-09-17 19:22:31,897 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts +2019-09-17 19:22:32,009 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts +2019-09-17 19:22:32,113 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts +2019-09-17 19:23:43,289 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts +2019-09-17 19:23:43,403 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts +2019-09-17 19:23:43,511 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts +2019-09-17 19:23:43,622 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts +2019-09-17 19:23:43,730 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts +2019-09-17 19:23:47,077 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts +2019-09-17 19:23:47,195 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts +2019-09-17 19:23:47,304 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts +2019-09-17 19:23:47,420 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts +2019-09-17 19:23:47,529 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts +2019-09-17 19:24:59,988 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts +2019-09-17 19:25:00,102 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts +2019-09-17 19:25:00,210 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts +2019-09-17 19:25:00,321 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts +2019-09-17 19:25:00,429 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts +2019-09-17 19:25:24,188 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts +2019-09-17 19:25:24,305 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts +2019-09-17 19:25:24,410 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts +2019-09-17 19:25:24,526 - nornir.core - INFO - run() - Running task 'custom_task_example' with args {} on 1 hosts +2019-09-17 19:25:24,635 - nornir.core - INFO - run() - Running task 'custom_task_example_2' with args {} on 1 hosts diff --git a/nornsible/__init__.py b/nornsible/__init__.py index c71e905..8c69aaf 100644 --- a/nornsible/__init__.py +++ b/nornsible/__init__.py @@ -3,16 +3,24 @@ from logging import NullHandler from nornsible.nornsible import ( - Init_Nornsible, + InitNornsible, parse_cli_args, - process_tags, + nornsible_task, patch_config, patch_inventory, + nornsible_task_message, ) -__version__ = "2019.09.16" -__all__ = ("Init_Nornsible", "parse_cli_args", "process_tags", "patch_config", "patch_inventory") +__version__ = "2019.09.17" +__all__ = ( + "InitNornsible", + "parse_cli_args", + "nornsible_task", + "patch_config", + "patch_inventory", + "nornsible_task_message", +) # Setup logger diff --git a/nornsible/nornsible.py b/nornsible/nornsible.py index ab5c2cf..7b8a540 100644 --- a/nornsible/nornsible.py +++ b/nornsible/nornsible.py @@ -1,24 +1,23 @@ import argparse -import logging import sys import threading +from typing import Dict, List, Any, Union, Callable -from colorama import Fore, Style, init +from colorama import Back, Fore, init, Style +from nornir.core import Nornir, Config, Inventory +from nornir.core.task import Task from nornir.core.task import Result - -session_log = logging.getLogger(__name__) - init(autoreset=True, strip=False) LOCK = threading.Lock() -def parse_cli_args(args: list) -> dict: +def parse_cli_args(raw_args: List[str]) -> dict: """ Parse CLI provided arguments; ignore unrecognized. Arguments: - args: List of CLI provided arguments + raw_args: List of CLI provided arguments Returns: cli_args: Processed CLI arguments @@ -53,17 +52,18 @@ def parse_cli_args(args: list) -> dict: "-t", "--tags", help="names of tasks to explicitly run", type=str.lower, default="" ) parser.add_argument("-s", "--skip", help="names of tasks to skip", type=str.lower, default="") - args, _ = parser.parse_known_args(args) - cli_args = {} - cli_args["workers"] = args.workers if args.workers else False - cli_args["limit"] = set(args.limit.split(",")) if args.limit else False - cli_args["groups"] = set(args.groups.split(",")) if args.groups else False - cli_args["run_tags"] = set(args.tags.split(",")) if args.tags else [] - cli_args["skip_tags"] = set(args.skip.split(",")) if args.skip else [] + args, _ = parser.parse_known_args(raw_args) + cli_args = { + "workers": args.workers if args.workers else False, + "limit": set(args.limit.split(",")) if args.limit else False, + "groups": set(args.groups.split(",")) if args.groups else False, + "run_tags": set(args.tags.split(",")) if args.tags else [], + "skip_tags": set(args.skip.split(",")) if args.skip else [], + } return cli_args -def patch_inventory(cli_args: dict, inv): +def patch_inventory(cli_args: dict, inv: Inventory) -> Inventory: """ Patch nornir inventory configurations per cli arguments. @@ -105,7 +105,7 @@ def patch_inventory(cli_args: dict, inv): return inv -def patch_config(cli_args: dict, conf): +def patch_config(cli_args: dict, conf: Config) -> Config: """ Patch nornir core configurations per cli arguments. @@ -126,9 +126,9 @@ def patch_config(cli_args: dict, conf): return conf -def process_tags_messages(msg): +def nornsible_task_message(msg: str) -> None: """ - Handle printing pretty messages for process_tags decorator + Handle printing pretty messages for nornsible_task decorator Args: msg: message to beautifully print to stdout @@ -142,12 +142,12 @@ def process_tags_messages(msg): """ LOCK.acquire() try: - print("{}{}{}{}".format(Style.BRIGHT, Fore.CYAN, msg, "-" * (80 - len(msg)))) + print(f"{Style.BRIGHT}{Back.CYAN}{Fore.WHITE}{msg}{'-' * (80 - len(msg))}") finally: LOCK.release() -def process_tags(wrapped_func): +def nornsible_task(wrapped_func: Callable) -> Callable: """ Decorate an "operation" -- execute or skip the operation based on tags @@ -162,24 +162,26 @@ def process_tags(wrapped_func): """ - def tag_wrapper(task, *args, **kwargs): - if set([wrapped_func.__name__]).intersection(task.nornir.skip_tags): + def tag_wrapper( + task: Task, *args: List[Any], **kwargs: Dict[str, Any] + ) -> Union[Callable, Result]: + if {wrapped_func.__name__}.intersection(task.nornir.skip_tags): msg = f"---- {task.host} skipping task {wrapped_func.__name__} " - process_tags_messages(msg) + nornsible_task_message(msg) return Result(host=task.host, result="Task skipped!", failed=False, changed=False) if not task.nornir.run_tags: return wrapped_func(task, *args, **kwargs) - if set([wrapped_func.__name__]).intersection(task.nornir.run_tags): + if {wrapped_func.__name__}.intersection(task.nornir.run_tags): return wrapped_func(task, *args, **kwargs) msg = f"---- {task.host} skipping task {wrapped_func.__name__} " - process_tags_messages(msg) + nornsible_task_message(msg) return Result(host=task.host, result="Task skipped!", failed=False, changed=False) tag_wrapper.__name__ = wrapped_func.__name__ return tag_wrapper -def Init_Nornsible(nr): +def InitNornsible(nr: Nornir) -> Nornir: """ Patch nornir object based on cli arguments diff --git a/requirements-dev.txt b/requirements-dev.txt index 4e6b1a1..788b5a3 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -7,6 +7,7 @@ pycodestyle>=2.5.0 pydocstyle>=4.0.1 pylint>=2.3.1 darglint>=0.6.1 +mypy>=0.720 +mypy-extensions>=0.4.1 pdoc3>=0.6.2 -nornir>=2.2.0 -r requirements.txt diff --git a/requirements.txt b/requirements.txt index e24644a..55db6b9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,2 @@ colorama>=0.3.9 +nornir>=2.2.0 \ No newline at end of file diff --git a/setup.cfg b/setup.cfg index dd0da5c..702010d 100644 --- a/setup.cfg +++ b/setup.cfg @@ -17,8 +17,16 @@ docstring_style = google [mypy] python_version = 3.7 -strict_optional = False +check_untyped_defs = True disallow_any_generics = False +disallow_untyped_calls = True +disallow_untyped_defs = True +disallow_incomplete_defs = True +disallow_untyped_decorators = True +ignore_errors = False ignore_missing_imports = True -warn_redundant_casts = True +strict_optional = True warn_unused_configs = True +warn_unused_ignores = True +warn_return_any = True +warn_redundant_casts = True diff --git a/setup.py b/setup.py index fb50d69..89ed281 100644 --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ setuptools.setup( name="nornsible", - version="2019.09.16", + version="2019.09.17", author=__author__, author_email="carl.r.montanari@gmail.com", description="Wrapper for tags and host/group limiting for nornir scripts.", diff --git a/tests/integration/test_nornsible_integration.py b/tests/integration/test_nornsible_integration.py new file mode 100644 index 0000000..f3df08f --- /dev/null +++ b/tests/integration/test_nornsible_integration.py @@ -0,0 +1,86 @@ +from pathlib import Path +import sys +from unittest.mock import patch + +from nornir import InitNornir + +import nornsible +from nornsible import InitNornsible, nornsible_task + + +NORNSIBLE_DIR = nornsible.__file__ +TEST_DIR = f"{Path(NORNSIBLE_DIR).parents[1]}/tests/" + + +@nornsible_task +def custom_task_example(task): + return "Hello, world!" + + +@nornsible_task +def custom_task_example_2(task): + return "Hello, world!" + + +def test_tags_wrapper_skip_task(): + testargs = ["somescript", "-l", "localhost", "-s", "custom_task_example"] + with patch.object(sys, "argv", testargs): + nr = InitNornir( + inventory={ + "plugin": "nornir.plugins.inventory.simple.SimpleInventory", + "options": { + "host_file": f"{TEST_DIR}_test_nornir_inventory/hosts.yaml", + "group_file": f"{TEST_DIR}_test_nornir_inventory/groups.yaml", + }, + } + ) + nr = InitNornsible(nr) + task_result = nr.run(task=custom_task_example) + assert set(task_result.keys()) == {"localhost"} + assert task_result["localhost"].result == "Task skipped!" + + +def test_tags_wrapper_explicit_task(): + testargs = ["somescript", "-l", "localhost", "-t", "custom_task_example_2"] + with patch.object(sys, "argv", testargs): + nr = InitNornir( + inventory={ + "plugin": "nornir.plugins.inventory.simple.SimpleInventory", + "options": { + "host_file": f"{TEST_DIR}_test_nornir_inventory/hosts.yaml", + "group_file": f"{TEST_DIR}_test_nornir_inventory/groups.yaml", + }, + } + ) + nr = InitNornsible(nr) + print(nr.inventory.hosts) + tasks = [custom_task_example, custom_task_example_2] + task_results = [] + for task in tasks: + task_results.append(nr.run(task=task)) + + assert task_results[0]["localhost"].result == "Task skipped!" + assert task_results[1]["localhost"].result == "Hello, world!" + + +def test_tags_wrapper_no_tags(): + testargs = ["somescript", "-l", "localhost"] + with patch.object(sys, "argv", testargs): + nr = InitNornir( + inventory={ + "plugin": "nornir.plugins.inventory.simple.SimpleInventory", + "options": { + "host_file": f"{TEST_DIR}_test_nornir_inventory/hosts.yaml", + "group_file": f"{TEST_DIR}_test_nornir_inventory/groups.yaml", + }, + } + ) + nr = InitNornsible(nr) + print(nr.inventory.hosts) + tasks = [custom_task_example, custom_task_example_2] + task_results = [] + for task in tasks: + task_results.append(nr.run(task=task)) + + assert task_results[0]["localhost"].result == "Hello, world!" + assert task_results[1]["localhost"].result == "Hello, world!" diff --git a/tests/test_nornsible.py b/tests/unit/test_nornsible_unit.py similarity index 71% rename from tests/test_nornsible.py rename to tests/unit/test_nornsible_unit.py index ce51227..05dd8cb 100644 --- a/tests/test_nornsible.py +++ b/tests/unit/test_nornsible_unit.py @@ -1,27 +1,24 @@ from pathlib import Path import sys +import threading from unittest.mock import patch from nornir import InitNornir import nornsible -from nornsible import Init_Nornsible, parse_cli_args, process_tags, patch_config, patch_inventory +from nornsible import ( + InitNornsible, + parse_cli_args, + patch_config, + patch_inventory, + nornsible_task_message, +) NORNSIBLE_DIR = nornsible.__file__ TEST_DIR = f"{Path(NORNSIBLE_DIR).parents[1]}/tests/" -@process_tags -def custom_task_example(task): - return "Hello, world!" - - -@process_tags -def custom_task_example_2(task): - return "Hello, world!" - - def test_parse_cli_args_basic_short(): args = [ "-l", @@ -166,7 +163,7 @@ def test_set_nornsible_limit_host(): }, } ) - nr = Init_Nornsible(nr) + nr = InitNornsible(nr) assert set(nr.inventory.hosts.keys()) == {"sea-eos-1"} @@ -182,7 +179,7 @@ def test_set_nornsible_limit_group(): }, } ) - nr = Init_Nornsible(nr) + nr = InitNornsible(nr) assert set(nr.inventory.hosts.keys()) == {"sea-eos-1"} @@ -198,7 +195,7 @@ def test_set_nornsible_workers(): }, } ) - nr = Init_Nornsible(nr) + nr = InitNornsible(nr) assert nr.config.core.num_workers == 10 @@ -214,7 +211,7 @@ def test_set_nornsible_limithost_invalid(): }, } ) - nr = Init_Nornsible(nr) + nr = InitNornsible(nr) assert set(nr.inventory.hosts.keys()) == set() @@ -230,7 +227,7 @@ def test_set_nornsible_limit_group_invalid(): }, } ) - nr = Init_Nornsible(nr) + nr = InitNornsible(nr) assert set(nr.inventory.hosts.keys()) == set() @@ -246,69 +243,11 @@ def test_set_nornsible_do_nothing(): }, } ) - nornsible_nr = Init_Nornsible(initial_nr) + nornsible_nr = InitNornsible(initial_nr) assert nornsible_nr == initial_nr -def test_tags_wrapper_skip_task(): - testargs = ["somescript", "-l", "localhost", "-s", "custom_task_example"] - with patch.object(sys, "argv", testargs): - nr = InitNornir( - inventory={ - "plugin": "nornir.plugins.inventory.simple.SimpleInventory", - "options": { - "host_file": f"{TEST_DIR}_test_nornir_inventory/hosts.yaml", - "group_file": f"{TEST_DIR}_test_nornir_inventory/groups.yaml", - }, - } - ) - nr = Init_Nornsible(nr) - task_result = nr.run(task=custom_task_example) - assert set(task_result.keys()) == {"localhost"} - assert task_result["localhost"].result == "Task skipped!" - - -def test_tags_wrapper_explicit_task(): - testargs = ["somescript", "-l", "localhost", "-t", "custom_task_example_2"] - with patch.object(sys, "argv", testargs): - nr = InitNornir( - inventory={ - "plugin": "nornir.plugins.inventory.simple.SimpleInventory", - "options": { - "host_file": f"{TEST_DIR}_test_nornir_inventory/hosts.yaml", - "group_file": f"{TEST_DIR}_test_nornir_inventory/groups.yaml", - }, - } - ) - nr = Init_Nornsible(nr) - print(nr.inventory.hosts) - tasks = [custom_task_example, custom_task_example_2] - task_results = [] - for task in tasks: - task_results.append(nr.run(task=task)) - - assert task_results[0]["localhost"].result == "Task skipped!" - assert task_results[1]["localhost"].result == "Hello, world!" - - -def test_tags_wrapper_no_tags(): - testargs = ["somescript", "-l", "localhost"] - with patch.object(sys, "argv", testargs): - nr = InitNornir( - inventory={ - "plugin": "nornir.plugins.inventory.simple.SimpleInventory", - "options": { - "host_file": f"{TEST_DIR}_test_nornir_inventory/hosts.yaml", - "group_file": f"{TEST_DIR}_test_nornir_inventory/groups.yaml", - }, - } - ) - nr = Init_Nornsible(nr) - print(nr.inventory.hosts) - tasks = [custom_task_example, custom_task_example_2] - task_results = [] - for task in tasks: - task_results.append(nr.run(task=task)) - - assert task_results[0]["localhost"].result == "Hello, world!" - assert task_results[1]["localhost"].result == "Hello, world!" +def test_process_tags_messages(capfd): + nornsible_task_message("this is a test message") + std_out, std_err = capfd.readouterr() + assert "this is a test message" in std_out diff --git a/tox.ini b/tox.ini index 8cf94ca..88e2965 100644 --- a/tox.ini +++ b/tox.ini @@ -23,3 +23,4 @@ commands = python -m pylama . python -m pydocstyle . darglint nornsible/. + python -m mypy nornsible/.