diff --git a/README.rst b/README.rst index f5096ce..cecf961 100644 --- a/README.rst +++ b/README.rst @@ -31,6 +31,9 @@ _________ * **print_result** - Formats nicely and prints results on stdout. * **print_title** - Formats nicely a title and prints it on stdout. +* **print_stat** - Prints results statistic on stdout. +* **write_result** - Writes results to file. +* **write_results** - Writes results to files. Processors __________ diff --git a/docs/source/tutorials/function_print_result.ipynb b/docs/source/tutorials/function_print_result.ipynb index e284ae5..e8b9ccc 100644 --- a/docs/source/tutorials/function_print_result.ipynb +++ b/docs/source/tutorials/function_print_result.ipynb @@ -50,28 +50,28 @@ "name": "stdout", "output_type": "stream", "text": [ - "\u001b[1m\u001b[36mdummy_task**********************************************************************\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[34m* dev1.group_1 ** changed : False **********************************************\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32mvvvv dummy_task ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO\u001b[0m\n", - "\u001b[0mhi!!!\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32m^^^^ END dummy_task ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[34m* dev2.group_1 ** changed : False **********************************************\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32mvvvv dummy_task ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO\u001b[0m\n", - "\u001b[0mhi!!!\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32m^^^^ END dummy_task ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[34m* dev3.group_2 ** changed : False **********************************************\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32mvvvv dummy_task ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO\u001b[0m\n", - "\u001b[0mhi!!!\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32m^^^^ END dummy_task ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[34m* dev4.group_2 ** changed : False **********************************************\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32mvvvv dummy_task ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO\u001b[0m\n", - "\u001b[0mhi!!!\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32m^^^^ END dummy_task ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[34m* dev5.no_group ** changed : False *********************************************\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32mvvvv dummy_task ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO\u001b[0m\n", - "\u001b[0mhi!!!\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32m^^^^ END dummy_task ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\n", - "\u001b[0m" + "\u001b[1m\u001b[36mdummy_task**********************************************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[34m* dev1.group_1 ** changed : False **********************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32mvvvv dummy_task ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mhi!!!\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m^^^^ END dummy_task ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[34m* dev2.group_1 ** changed : False **********************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32mvvvv dummy_task ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mhi!!!\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m^^^^ END dummy_task ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[34m* dev3.group_2 ** changed : False **********************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32mvvvv dummy_task ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mhi!!!\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m^^^^ END dummy_task ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[34m* dev4.group_2 ** changed : False **********************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32mvvvv dummy_task ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mhi!!!\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m^^^^ END dummy_task ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[34m* dev5.no_group ** changed : False *********************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32mvvvv dummy_task ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mhi!!!\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m^^^^ END dummy_task ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m" ] } ], @@ -99,33 +99,33 @@ "name": "stdout", "output_type": "stream", "text": [ - "\u001b[1m\u001b[36mtask_with_data******************************************************************\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[34m* dev1.group_1 ** changed : False **********************************************\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32mvvvv task_with_data ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO\u001b[0m\n", - "\u001b[0mJar Jar Binks\u001b[0m\n", - "\u001b[0mhawaiian pizza\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32m^^^^ END task_with_data ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[34m* dev2.group_1 ** changed : False **********************************************\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32mvvvv task_with_data ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO\u001b[0m\n", - "\u001b[0mJar Jar Binks\u001b[0m\n", - "\u001b[0mhawaiian pizza\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32m^^^^ END task_with_data ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[34m* dev3.group_2 ** changed : False **********************************************\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32mvvvv task_with_data ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO\u001b[0m\n", - "\u001b[0mJar Jar Binks\u001b[0m\n", - "\u001b[0mhawaiian pizza\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32m^^^^ END task_with_data ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[34m* dev4.group_2 ** changed : False **********************************************\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32mvvvv task_with_data ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO\u001b[0m\n", - "\u001b[0mJar Jar Binks\u001b[0m\n", - "\u001b[0mhawaiian pizza\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32m^^^^ END task_with_data ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[34m* dev5.no_group ** changed : False *********************************************\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32mvvvv task_with_data ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO\u001b[0m\n", - "\u001b[0mJar Jar Binks\u001b[0m\n", - "\u001b[0mhawaiian pizza\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32m^^^^ END task_with_data ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\n", - "\u001b[0m" + "\u001b[1m\u001b[36mtask_with_data******************************************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[34m* dev1.group_1 ** changed : False **********************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32mvvvv task_with_data ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mJar Jar Binks\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mhawaiian pizza\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m^^^^ END task_with_data ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[34m* dev2.group_1 ** changed : False **********************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32mvvvv task_with_data ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mJar Jar Binks\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mhawaiian pizza\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m^^^^ END task_with_data ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[34m* dev3.group_2 ** changed : False **********************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32mvvvv task_with_data ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mJar Jar Binks\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mhawaiian pizza\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m^^^^ END task_with_data ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[34m* dev4.group_2 ** changed : False **********************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32mvvvv task_with_data ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mJar Jar Binks\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mhawaiian pizza\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m^^^^ END task_with_data ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[34m* dev5.no_group ** changed : False *********************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32mvvvv task_with_data ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mJar Jar Binks\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mhawaiian pizza\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m^^^^ END task_with_data ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m" ] } ], @@ -185,28 +185,28 @@ "name": "stdout", "output_type": "stream", "text": [ - "\u001b[1m\u001b[36mcomplex_task********************************************************************\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[34m* dev1.group_1 ** changed : False **********************************************\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32mvvvv complex_task ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO\u001b[0m\n", - "\u001b[0mI did a lot of things!!!\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32m^^^^ END complex_task ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[34m* dev2.group_1 ** changed : False **********************************************\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32mvvvv complex_task ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO\u001b[0m\n", - "\u001b[0mI did a lot of things!!!\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32m^^^^ END complex_task ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[34m* dev3.group_2 ** changed : False **********************************************\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32mvvvv complex_task ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO\u001b[0m\n", - "\u001b[0mI did a lot of things!!!\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32m^^^^ END complex_task ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[34m* dev4.group_2 ** changed : False **********************************************\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32mvvvv complex_task ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO\u001b[0m\n", - "\u001b[0mI did a lot of things!!!\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32m^^^^ END complex_task ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[34m* dev5.no_group ** changed : False *********************************************\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32mvvvv complex_task ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO\u001b[0m\n", - "\u001b[0mI did a lot of things!!!\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32m^^^^ END complex_task ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\n", - "\u001b[0m" + "\u001b[1m\u001b[36mcomplex_task********************************************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[34m* dev1.group_1 ** changed : False **********************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32mvvvv complex_task ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mI did a lot of things!!!\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m^^^^ END complex_task ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[34m* dev2.group_1 ** changed : False **********************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32mvvvv complex_task ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mI did a lot of things!!!\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m^^^^ END complex_task ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[34m* dev3.group_2 ** changed : False **********************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32mvvvv complex_task ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mI did a lot of things!!!\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m^^^^ END complex_task ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[34m* dev4.group_2 ** changed : False **********************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32mvvvv complex_task ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mI did a lot of things!!!\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m^^^^ END complex_task ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[34m* dev5.no_group ** changed : False *********************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32mvvvv complex_task ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mI did a lot of things!!!\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m^^^^ END complex_task ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m" ] } ], @@ -230,89 +230,154 @@ "name": "stdout", "output_type": "stream", "text": [ - "\u001b[1m\u001b[36mcomplex_task********************************************************************\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[34m* dev1.group_1 ** changed : False **********************************************\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32mvvvv complex_task ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO\u001b[0m\n", - "\u001b[0mI did a lot of things!!!\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\n", - "\u001b[0mhi!!!\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\n", - "\u001b[0mhi!!!\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\n", - "\u001b[0mhi!!!\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\n", - "\u001b[0mhi!!!\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\n", - "\u001b[0mhi!!!\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32m^^^^ END complex_task ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[34m* dev2.group_1 ** changed : False **********************************************\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32mvvvv complex_task ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO\u001b[0m\n", - "\u001b[0mI did a lot of things!!!\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\n", - "\u001b[0mhi!!!\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\n", - "\u001b[0mhi!!!\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\n", - "\u001b[0mhi!!!\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\n", - "\u001b[0mhi!!!\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\n", - "\u001b[0mhi!!!\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32m^^^^ END complex_task ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[34m* dev3.group_2 ** changed : False **********************************************\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32mvvvv complex_task ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO\u001b[0m\n", - "\u001b[0mI did a lot of things!!!\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\n", - "\u001b[0mhi!!!\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\n", - "\u001b[0mhi!!!\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\n", - "\u001b[0mhi!!!\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\n", - "\u001b[0mhi!!!\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\n", - "\u001b[0mhi!!!\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32m^^^^ END complex_task ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[34m* dev4.group_2 ** changed : False **********************************************\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32mvvvv complex_task ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO\u001b[0m\n", - "\u001b[0mI did a lot of things!!!\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\n", - "\u001b[0mhi!!!\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\n", - "\u001b[0mhi!!!\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\n", - "\u001b[0mhi!!!\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\n", - "\u001b[0mhi!!!\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\n", - "\u001b[0mhi!!!\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32m^^^^ END complex_task ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[34m* dev5.no_group ** changed : False *********************************************\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32mvvvv complex_task ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO\u001b[0m\n", - "\u001b[0mI did a lot of things!!!\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\n", - "\u001b[0mhi!!!\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\n", - "\u001b[0mhi!!!\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\n", - "\u001b[0mhi!!!\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\n", - "\u001b[0mhi!!!\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\n", - "\u001b[0mhi!!!\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[32m^^^^ END complex_task ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\n", - "\u001b[0m" + "\u001b[1m\u001b[36mcomplex_task********************************************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[34m* dev1.group_1 ** changed : False **********************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32mvvvv complex_task ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mI did a lot of things!!!\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mhi!!!\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mhi!!!\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mhi!!!\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mhi!!!\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mhi!!!\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m^^^^ END complex_task ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[34m* dev2.group_1 ** changed : False **********************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32mvvvv complex_task ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mI did a lot of things!!!\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mhi!!!\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mhi!!!\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mhi!!!\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mhi!!!\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mhi!!!\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m^^^^ END complex_task ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[34m* dev3.group_2 ** changed : False **********************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32mvvvv complex_task ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mI did a lot of things!!!\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mhi!!!\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mhi!!!\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mhi!!!\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mhi!!!\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mhi!!!\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m^^^^ END complex_task ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[34m* dev4.group_2 ** changed : False **********************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32mvvvv complex_task ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mI did a lot of things!!!\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mhi!!!\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mhi!!!\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mhi!!!\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mhi!!!\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mhi!!!\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m^^^^ END complex_task ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[34m* dev5.no_group ** changed : False *********************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32mvvvv complex_task ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mI did a lot of things!!!\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mhi!!!\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mhi!!!\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mhi!!!\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mhi!!!\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m---- dummy_task ** changed : False --------------------------------------------- DEBUG\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mhi!!!\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m^^^^ END complex_task ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m" ] } ], "source": [ "print_result(complex_result, severity_level=logging.DEBUG)" ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Count\n", + "\n", + "You can limit the output without changing scrollback terminal settings:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[1m\u001b[36mcomplex_task********************************************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[34m* dev1.group_1 ** changed : False **********************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32mvvvv complex_task ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mI did a lot of things!!!\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m^^^^ END complex_task ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[34m* dev2.group_1 ** changed : False **********************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32mvvvv complex_task ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mI did a lot of things!!!\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m^^^^ END complex_task ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m" + ] + } + ], + "source": [ + "print_result(complex_result, count=2)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[1m\u001b[36mcomplex_task********************************************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[34m* dev3.group_2 ** changed : False **********************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32mvvvv complex_task ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mI did a lot of things!!!\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m^^^^ END complex_task ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[34m* dev4.group_2 ** changed : False **********************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32mvvvv complex_task ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mI did a lot of things!!!\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m^^^^ END complex_task ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[34m* dev5.no_group ** changed : False *********************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32mvvvv complex_task ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0mI did a lot of things!!!\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32m^^^^ END complex_task ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m" + ] + } + ], + "source": [ + "print_result(complex_result, count=-3)" + ] } ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -326,7 +391,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.2" + "version": "3.8.5" } }, "nbformat": 4, diff --git a/docs/source/tutorials/function_print_stat.ipynb b/docs/source/tutorials/function_print_stat.ipynb new file mode 100644 index 0000000..b02affe --- /dev/null +++ b/docs/source/tutorials/function_print_stat.ipynb @@ -0,0 +1,285 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "57c50027", + "metadata": {}, + "source": [ + "# functions: print_stat.py\n", + "\n", + "[print_stat](../api/functions.rst#nornir_utils.plugins.functions.print_stat) is a function that prints result statistic:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "846f5194", + "metadata": {}, + "outputs": [], + "source": [ + "from nornir import InitNornir\n", + "\n", + "def dummy_task(task):\n", + " return \"hi!!!\"\n", + "\n", + "nr = InitNornir(\n", + " inventory={\n", + " \"plugin\":\"YAMLInventory\",\n", + " \"options\": {\n", + " \"host_file\": \"data/hosts.yaml\",\n", + " \"group_file\": \"data/groups.yaml\",\n", + " \"defaults_file\": \"data/defaults.yaml\",\n", + " }\n", + " }\n", + ")\n", + "\n", + "result = nr.run(task=dummy_task)" + ] + }, + { + "cell_type": "markdown", + "id": "eaf219ba", + "metadata": {}, + "source": [ + "Now we could print the result statistic easily with the `print_stat` function: " + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "ab8f58ca", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[1m\u001b[36mdummy_task**********************************************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[34m* dev1.group_1 *****************************************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m \u001b[1m\u001b[32mdummy_task ok=1 changed=0 failed=0 \u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[34m* dev2.group_1 *****************************************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m \u001b[1m\u001b[32mdummy_task ok=1 changed=0 failed=0 \u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[34m* dev3.group_2 *****************************************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m \u001b[1m\u001b[32mdummy_task ok=1 changed=0 failed=0 \u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[34m* dev4.group_2 *****************************************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m \u001b[1m\u001b[32mdummy_task ok=1 changed=0 failed=0 \u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[34m* dev5.no_group ****************************************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m \u001b[1m\u001b[32mdummy_task ok=1 changed=0 failed=0 \u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32mOK : 5\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[33mCHANGED : 0\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[31mFAILED : 0\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m" + ] + } + ], + "source": [ + "from nornir_utils.plugins.functions import print_stat\n", + "\n", + "print_stat(result)" + ] + }, + { + "cell_type": "markdown", + "id": "03d245e5", + "metadata": {}, + "source": [ + "If the task returns changed or failed results, you can see it:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "d6fa941a", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[1m\u001b[36mdummy_task**********************************************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[34m* dev1.group_1 *****************************************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m \u001b[1m\u001b[33mdummy_task ok=1 changed=1 failed=0 \u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[34m* dev2.group_1 *****************************************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m \u001b[1m\u001b[31mdummy_task ok=0 changed=0 failed=1 \u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[34m* dev3.group_2 *****************************************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m \u001b[1m\u001b[32mdummy_task ok=1 changed=0 failed=0 \u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[34m* dev4.group_2 *****************************************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m \u001b[1m\u001b[31mdummy_task ok=0 changed=0 failed=1 \u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[34m* dev5.no_group ****************************************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m \u001b[1m\u001b[32mdummy_task ok=1 changed=0 failed=0 \u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32mOK : 3\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[33mCHANGED : 1\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[31mFAILED : 2\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m" + ] + } + ], + "source": [ + "result[\"dev1.group_1\"][0].changed=True\n", + "result[\"dev2.group_1\"][0].failed=True\n", + "result[\"dev4.group_2\"][0].failed=True\n", + "\n", + "print_stat(result)" + ] + }, + { + "cell_type": "markdown", + "id": "948feecb", + "metadata": {}, + "source": [ + "If `MultiResult` object contains multiple `Result` objects:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "0d811189", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[1m\u001b[36msmart_task**********************************************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[34m* dev1.group_1 *****************************************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m \u001b[1m\u001b[31msmart_task ok=0 changed=0 failed=1 \u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m \u001b[1m\u001b[32mdummy_task ok=1 changed=0 failed=0 \u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m \u001b[1m\u001b[32mdummy_task ok=1 changed=0 failed=0 \u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m \u001b[1m\u001b[32mdummy_task ok=1 changed=0 failed=0 \u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m \u001b[1m\u001b[31mdummy_task ok=0 changed=0 failed=1 \u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[34m* dev2.group_1 *****************************************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m \u001b[1m\u001b[31msmart_task ok=0 changed=0 failed=1 \u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m \u001b[1m\u001b[32mdummy_task ok=1 changed=0 failed=0 \u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m \u001b[1m\u001b[32mdummy_task ok=1 changed=0 failed=0 \u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m \u001b[1m\u001b[32mdummy_task ok=1 changed=0 failed=0 \u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m \u001b[1m\u001b[31mdummy_task ok=0 changed=0 failed=1 \u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[34m* dev3.group_2 *****************************************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m \u001b[1m\u001b[31msmart_task ok=0 changed=0 failed=1 \u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m \u001b[1m\u001b[32mdummy_task ok=1 changed=0 failed=0 \u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m \u001b[1m\u001b[32mdummy_task ok=1 changed=0 failed=0 \u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m \u001b[1m\u001b[32mdummy_task ok=1 changed=0 failed=0 \u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m \u001b[1m\u001b[31mdummy_task ok=0 changed=0 failed=1 \u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[34m* dev4.group_2 *****************************************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m \u001b[1m\u001b[31msmart_task ok=0 changed=0 failed=1 \u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m \u001b[1m\u001b[32mdummy_task ok=1 changed=0 failed=0 \u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m \u001b[1m\u001b[32mdummy_task ok=1 changed=0 failed=0 \u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m \u001b[1m\u001b[32mdummy_task ok=1 changed=0 failed=0 \u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m \u001b[1m\u001b[31mdummy_task ok=0 changed=0 failed=1 \u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[34m* dev5.no_group ****************************************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m \u001b[1m\u001b[31msmart_task ok=0 changed=0 failed=1 \u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m \u001b[1m\u001b[32mdummy_task ok=1 changed=0 failed=0 \u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m \u001b[1m\u001b[32mdummy_task ok=1 changed=0 failed=0 \u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m \u001b[1m\u001b[32mdummy_task ok=1 changed=0 failed=0 \u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m \u001b[1m\u001b[31mdummy_task ok=0 changed=0 failed=1 \u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32mOK : 15\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[33mCHANGED : 0\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[31mFAILED : 10\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m" + ] + } + ], + "source": [ + "def smart_task(task):\n", + " task.run(task=dummy_task)\n", + " task.run(task=dummy_task)\n", + " task.run(task=dummy_task)\n", + " task.run(task=dummy_task, failed=True)\n", + " return \"hihi!!!\"\n", + "\n", + "\n", + "smart_task_result = nr.run(task=smart_task)\n", + "\n", + "print_stat(smart_task_result)" + ] + }, + { + "cell_type": "markdown", + "id": "5b260107", + "metadata": {}, + "source": [ + "## Count\n", + "You can limit the statistic output without changing scrollback terminal settings:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "ef857b5d", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[1m\u001b[36mdummy_task**********************************************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[34m* dev1.group_1 *****************************************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m \u001b[1m\u001b[33mdummy_task ok=1 changed=1 failed=0 \u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[34m* dev2.group_1 *****************************************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m \u001b[1m\u001b[31mdummy_task ok=0 changed=0 failed=1 \u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32mOK : 1\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[33mCHANGED : 1\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[31mFAILED : 1\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m" + ] + } + ], + "source": [ + "print_stat(result, count=2)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "a1be4aaa", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[1m\u001b[36mdummy_task**********************************************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[34m* dev3.group_2 *****************************************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m \u001b[1m\u001b[32mdummy_task ok=1 changed=0 failed=0 \u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[34m* dev4.group_2 *****************************************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m \u001b[1m\u001b[31mdummy_task ok=0 changed=0 failed=1 \u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[34m* dev5.no_group ****************************************************************\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m \u001b[1m\u001b[32mdummy_task ok=1 changed=0 failed=0 \u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[32mOK : 2\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[33mCHANGED : 0\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[1m\u001b[31mFAILED : 1\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m" + ] + } + ], + "source": [ + "print_stat(result, count=-3)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/source/tutorials/function_write_result.ipynb b/docs/source/tutorials/function_write_result.ipynb new file mode 100644 index 0000000..0873fad --- /dev/null +++ b/docs/source/tutorials/function_write_result.ipynb @@ -0,0 +1,975 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "2d2c17c5", + "metadata": {}, + "source": [ + "# functions: write_result\n", + "\n", + "[write_result](../api/functions.rst#nornir_utils.plugins.functions.write_result) is a function that writes result and returns diff between old file and new file:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "03a00337", + "metadata": {}, + "outputs": [], + "source": [ + "from nornir import InitNornir\n", + "\n", + "def dummy_task(task):\n", + " return \"hi!!!\"\n", + "\n", + "nr = InitNornir(\n", + " inventory={\n", + " \"plugin\":\"YAMLInventory\",\n", + " \"options\": {\n", + " \"host_file\": \"data/hosts.yaml\",\n", + " \"group_file\": \"data/groups.yaml\",\n", + " \"defaults_file\": \"data/defaults.yaml\",\n", + " }\n", + " }\n", + ")\n", + "\n", + "result = nr.run(task=dummy_task)" + ] + }, + { + "cell_type": "markdown", + "id": "57e43930", + "metadata": {}, + "source": [ + "Now we could write the result easily with the `write_result` function:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "cb99b478", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'--- out_files/write_result/result.txt\\n\\n+++ new\\n\\n@@ -0,0 +1,19 @@\\n\\n+---- dev1.group_1: dummy_task ** changed : False ------------------------------- INFO\\n+\\n+hi!!!\\n+\\n+---- dev2.group_1: dummy_task ** changed : False ------------------------------- INFO\\n+\\n+hi!!!\\n+\\n+---- dev3.group_2: dummy_task ** changed : False ------------------------------- INFO\\n+\\n+hi!!!\\n+\\n+---- dev4.group_2: dummy_task ** changed : False ------------------------------- INFO\\n+\\n+hi!!!\\n+\\n+---- dev5.no_group: dummy_task ** changed : False ------------------------------ INFO\\n+\\n+hi!!!'" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from nornir_utils.plugins.functions import write_result\n", + "\n", + "# write_result returns diff between the previous and current file state\n", + "write_result(result, filename=\"out_files/write_result/result.txt\")" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "5227fd1e", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "---- dev1.group_1: dummy_task ** changed : False ------------------------------- INFO\n", + "\n", + "hi!!!\n", + "\n", + "---- dev2.group_1: dummy_task ** changed : False ------------------------------- INFO\n", + "\n", + "hi!!!\n", + "\n", + "---- dev3.group_2: dummy_task ** changed : False ------------------------------- INFO\n", + "\n", + "hi!!!\n", + "\n", + "---- dev4.group_2: dummy_task ** changed : False ------------------------------- INFO\n", + "\n", + "hi!!!\n", + "\n", + "---- dev5.no_group: dummy_task ** changed : False ------------------------------ INFO\n", + "\n", + "hi!!!\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m" + ] + } + ], + "source": [ + "cat out_files/write_result/result.txt" + ] + }, + { + "cell_type": "markdown", + "id": "a1f86c3a", + "metadata": {}, + "source": [ + "`filename` here is path to file, you want to write the result. `write_result` creates directories from the path with filename, if it's necessary." + ] + }, + { + "cell_type": "markdown", + "id": "c47e072f", + "metadata": {}, + "source": [ + "## Diff\n", + "\n", + "As you can see, `write_result` returns diff between the previous and current file state:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "14c221c4", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "--- out_files/write_result/result.txt\n", + "\n", + "+++ new\n", + "\n", + "@@ -0,0 +1,19 @@\n", + "\n", + "+---- dev1.group_1: smart_task ** changed : False ------------------------------- INFO\n", + "+\n", + "+hihi!!!\n", + "+\n", + "+---- dev2.group_1: smart_task ** changed : False ------------------------------- INFO\n", + "+\n", + "+hihi!!!\n", + "+\n", + "+---- dev3.group_2: smart_task ** changed : False ------------------------------- INFO\n", + "+\n", + "+hihi!!!\n", + "+\n", + "+---- dev4.group_2: smart_task ** changed : False ------------------------------- INFO\n", + "+\n", + "+hihi!!!\n", + "+\n", + "+---- dev5.no_group: smart_task ** changed : False ------------------------------ INFO\n", + "+\n", + "+hihi!!!\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m" + ] + } + ], + "source": [ + "def smart_task(task):\n", + " return \"hihi!!!\"\n", + "\n", + "result = nr.run(task=smart_task)\n", + "\n", + "print(write_result(result, filename=\"out_files/write_result/result.txt\"))" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "d234c3c3", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "---- dev1.group_1: smart_task ** changed : False ------------------------------- INFO\n", + "\n", + "hihi!!!\n", + "\n", + "---- dev2.group_1: smart_task ** changed : False ------------------------------- INFO\n", + "\n", + "hihi!!!\n", + "\n", + "---- dev3.group_2: smart_task ** changed : False ------------------------------- INFO\n", + "\n", + "hihi!!!\n", + "\n", + "---- dev4.group_2: smart_task ** changed : False ------------------------------- INFO\n", + "\n", + "hihi!!!\n", + "\n", + "---- dev5.no_group: smart_task ** changed : False ------------------------------ INFO\n", + "\n", + "hihi!!!\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m" + ] + } + ], + "source": [ + "cat out_files/write_result/result.txt" + ] + }, + { + "cell_type": "markdown", + "id": "231ce6f0", + "metadata": {}, + "source": [ + "## Writing specific data\n", + "\n", + "If the task returns different information, you can also select which ones to write. For instance:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "774eaef7", + "metadata": {}, + "outputs": [], + "source": [ + "from nornir.core.task import Result\n", + "\n", + "def task_with_data(task):\n", + " return Result(host=task.host, result=\"Spaghetti monster\", sw_char=\"Jar Jar Binks\", food=\"hawaiian pizza\", OS=\"windows\")\n", + "\n", + "\n", + "fav_result = nr.run(task=task_with_data)\n", + "\n", + "# write only sw_char, food vars and write diff to diff variable \n", + "diff = write_result(fav_result, filename=\"out_files/write_result/result.txt\", vars=[\"sw_char\", \"food\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "a1ac0f7f", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "---- dev1.group_1: task_with_data ** changed : False --------------------------- INFO\n", + "\n", + "Jar Jar Binks\n", + "\n", + "hawaiian pizza\n", + "\n", + "---- dev2.group_1: task_with_data ** changed : False --------------------------- INFO\n", + "\n", + "Jar Jar Binks\n", + "\n", + "hawaiian pizza\n", + "\n", + "---- dev3.group_2: task_with_data ** changed : False --------------------------- INFO\n", + "\n", + "Jar Jar Binks\n", + "\n", + "hawaiian pizza\n", + "\n", + "---- dev4.group_2: task_with_data ** changed : False --------------------------- INFO\n", + "\n", + "Jar Jar Binks\n", + "\n", + "hawaiian pizza\n", + "\n", + "---- dev5.no_group: task_with_data ** changed : False -------------------------- INFO\n", + "\n", + "Jar Jar Binks\n", + "\n", + "hawaiian pizza\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m" + ] + } + ], + "source": [ + "cat out_files/write_result/result.txt" + ] + }, + { + "cell_type": "markdown", + "id": "568719c8", + "metadata": {}, + "source": [ + "## Severity\n", + "\n", + "You can also ask `write_result` to write the results only if the severity is equal or superior to the one specified. This is particularly useful if your script is very large and you don't care about intermediate results. For instance:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "6dd24ac3", + "metadata": {}, + "outputs": [], + "source": [ + "import logging\n", + "\n", + "def complex_task(task):\n", + " task.run(task=dummy_task, severity_level=logging.DEBUG)\n", + " task.run(task=dummy_task, severity_level=logging.DEBUG)\n", + " task.run(task=dummy_task, severity_level=logging.DEBUG)\n", + " task.run(task=dummy_task, severity_level=logging.DEBUG)\n", + " task.run(task=dummy_task, severity_level=logging.DEBUG)\n", + " return \"I did a lot of things!!!\"\n", + "\n", + "complex_result = nr.run(task=complex_task)" + ] + }, + { + "cell_type": "markdown", + "id": "36d6d9c4", + "metadata": {}, + "source": [ + "`write_result` will only write `INFO` severity and above by default so if we write the result we should only see the result of the parent task:" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "9d33d258", + "metadata": {}, + "outputs": [], + "source": [ + "diff = write_result(complex_result, filename=\"out_files/write_result/result.txt\")" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "36f7b1c9", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "---- dev1.group_1: complex_task ** changed : False ----------------------------- INFO\n", + "\n", + "I did a lot of things!!!\n", + "\n", + "---- dev2.group_1: complex_task ** changed : False ----------------------------- INFO\n", + "\n", + "I did a lot of things!!!\n", + "\n", + "---- dev3.group_2: complex_task ** changed : False ----------------------------- INFO\n", + "\n", + "I did a lot of things!!!\n", + "\n", + "---- dev4.group_2: complex_task ** changed : False ----------------------------- INFO\n", + "\n", + "I did a lot of things!!!\n", + "\n", + "---- dev5.no_group: complex_task ** changed : False ---------------------------- INFO\n", + "\n", + "I did a lot of things!!!\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m" + ] + } + ], + "source": [ + "cat out_files/write_result/result.txt" + ] + }, + { + "cell_type": "markdown", + "id": "86998af3", + "metadata": {}, + "source": [ + "If you wanted to write all the tasks for debugging purposes you could specify it with:" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "f9c380ae", + "metadata": {}, + "outputs": [], + "source": [ + "diff = write_result(complex_result, filename=\"out_files/write_result/result.txt\", severity_level=logging.DEBUG)" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "3801974b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "---- dev1.group_1: complex_task ** changed : False ----------------------------- INFO\n", + "\n", + "I did a lot of things!!!\n", + "\n", + "---- dev1.group_1: dummy_task ** changed : False ------------------------------- DEBUG\n", + "\n", + "hi!!!\n", + "\n", + "---- dev1.group_1: dummy_task ** changed : False ------------------------------- DEBUG\n", + "\n", + "hi!!!\n", + "\n", + "---- dev1.group_1: dummy_task ** changed : False ------------------------------- DEBUG\n", + "\n", + "hi!!!\n", + "\n", + "---- dev1.group_1: dummy_task ** changed : False ------------------------------- DEBUG\n", + "\n", + "hi!!!\n", + "\n", + "---- dev1.group_1: dummy_task ** changed : False ------------------------------- DEBUG\n", + "\n", + "hi!!!\n", + "\n", + "---- dev2.group_1: complex_task ** changed : False ----------------------------- INFO\n", + "\n", + "I did a lot of things!!!\n", + "\n", + "---- dev2.group_1: dummy_task ** changed : False ------------------------------- DEBUG\n", + "\n", + "hi!!!\n", + "\n", + "---- dev2.group_1: dummy_task ** changed : False ------------------------------- DEBUG\n", + "\n", + "hi!!!\n", + "\n", + "---- dev2.group_1: dummy_task ** changed : False ------------------------------- DEBUG\n", + "\n", + "hi!!!\n", + "\n", + "---- dev2.group_1: dummy_task ** changed : False ------------------------------- DEBUG\n", + "\n", + "hi!!!\n", + "\n", + "---- dev2.group_1: dummy_task ** changed : False ------------------------------- DEBUG\n", + "\n", + "hi!!!\n", + "\n", + "---- dev3.group_2: complex_task ** changed : False ----------------------------- INFO\n", + "\n", + "I did a lot of things!!!\n", + "\n", + "---- dev3.group_2: dummy_task ** changed : False ------------------------------- DEBUG\n", + "\n", + "hi!!!\n", + "\n", + "---- dev3.group_2: dummy_task ** changed : False ------------------------------- DEBUG\n", + "\n", + "hi!!!\n", + "\n", + "---- dev3.group_2: dummy_task ** changed : False ------------------------------- DEBUG\n", + "\n", + "hi!!!\n", + "\n", + "---- dev3.group_2: dummy_task ** changed : False ------------------------------- DEBUG\n", + "\n", + "hi!!!\n", + "\n", + "---- dev3.group_2: dummy_task ** changed : False ------------------------------- DEBUG\n", + "\n", + "hi!!!\n", + "\n", + "---- dev4.group_2: complex_task ** changed : False ----------------------------- INFO\n", + "\n", + "I did a lot of things!!!\n", + "\n", + "---- dev4.group_2: dummy_task ** changed : False ------------------------------- DEBUG\n", + "\n", + "hi!!!\n", + "\n", + "---- dev4.group_2: dummy_task ** changed : False ------------------------------- DEBUG\n", + "\n", + "hi!!!\n", + "\n", + "---- dev4.group_2: dummy_task ** changed : False ------------------------------- DEBUG\n", + "\n", + "hi!!!\n", + "\n", + "---- dev4.group_2: dummy_task ** changed : False ------------------------------- DEBUG\n", + "\n", + "hi!!!\n", + "\n", + "---- dev4.group_2: dummy_task ** changed : False ------------------------------- DEBUG\n", + "\n", + "hi!!!\n", + "\n", + "---- dev5.no_group: complex_task ** changed : False ---------------------------- INFO\n", + "\n", + "I did a lot of things!!!\n", + "\n", + "---- dev5.no_group: dummy_task ** changed : False ------------------------------ DEBUG\n", + "\n", + "hi!!!\n", + "\n", + "---- dev5.no_group: dummy_task ** changed : False ------------------------------ DEBUG\n", + "\n", + "hi!!!\n", + "\n", + "---- dev5.no_group: dummy_task ** changed : False ------------------------------ DEBUG\n", + "\n", + "hi!!!\n", + "\n", + "---- dev5.no_group: dummy_task ** changed : False ------------------------------ DEBUG\n", + "\n", + "hi!!!\n", + "\n", + "---- dev5.no_group: dummy_task ** changed : False ------------------------------ DEBUG\n", + "\n", + "hi!!!\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m" + ] + } + ], + "source": [ + "cat out_files/write_result/result.txt" + ] + }, + { + "cell_type": "markdown", + "id": "44d096ef", + "metadata": {}, + "source": [ + "## Write host\n", + "\n", + "`write_host` argument can help you, if you don't need to write hostnames to file:" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "fb93e599", + "metadata": {}, + "outputs": [], + "source": [ + "diff = write_result(result, filename=\"out_files/write_result/result.txt\", write_host=False)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "1675db9a", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "---- smart_task ** changed : False --------------------------------------------- INFO\n", + "\n", + "hihi!!!\n", + "\n", + "---- smart_task ** changed : False --------------------------------------------- INFO\n", + "\n", + "hihi!!!\n", + "\n", + "---- smart_task ** changed : False --------------------------------------------- INFO\n", + "\n", + "hihi!!!\n", + "\n", + "---- smart_task ** changed : False --------------------------------------------- INFO\n", + "\n", + "hihi!!!\n", + "\n", + "---- smart_task ** changed : False --------------------------------------------- INFO\n", + "\n", + "hihi!!!\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m" + ] + } + ], + "source": [ + "cat out_files/write_result/result.txt" + ] + }, + { + "cell_type": "markdown", + "id": "34a824f1", + "metadata": {}, + "source": [ + "## Append\n", + "\n", + "`append` argument allows you to use `a+` or `w+` (default mode) writing mode. As instance:" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "62cbce4a", + "metadata": {}, + "outputs": [], + "source": [ + "diff = write_result(fav_result, filename=\"out_files/write_result/result.txt\", append=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "77bfdfba", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "---- smart_task ** changed : False --------------------------------------------- INFO\n", + "\n", + "hihi!!!\n", + "\n", + "---- smart_task ** changed : False --------------------------------------------- INFO\n", + "\n", + "hihi!!!\n", + "\n", + "---- smart_task ** changed : False --------------------------------------------- INFO\n", + "\n", + "hihi!!!\n", + "\n", + "---- smart_task ** changed : False --------------------------------------------- INFO\n", + "\n", + "hihi!!!\n", + "\n", + "---- smart_task ** changed : False --------------------------------------------- INFO\n", + "\n", + "hihi!!!\n", + "\n", + "---- dev1.group_1: task_with_data ** changed : False --------------------------- INFO\n", + "\n", + "Spaghetti monster\n", + "\n", + "---- dev2.group_1: task_with_data ** changed : False --------------------------- INFO\n", + "\n", + "Spaghetti monster\n", + "\n", + "---- dev3.group_2: task_with_data ** changed : False --------------------------- INFO\n", + "\n", + "Spaghetti monster\n", + "\n", + "---- dev4.group_2: task_with_data ** changed : False --------------------------- INFO\n", + "\n", + "Spaghetti monster\n", + "\n", + "---- dev5.no_group: task_with_data ** changed : False -------------------------- INFO\n", + "\n", + "Spaghetti monster\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m" + ] + } + ], + "source": [ + "cat out_files/write_result/result.txt" + ] + }, + { + "cell_type": "markdown", + "id": "57f5b76d", + "metadata": {}, + "source": [ + "# No errors\n", + "\n", + "Don't write errors to file with `no_errors` argument. As instance:" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "c9d3a814", + "metadata": {}, + "outputs": [], + "source": [ + "def task_with_exception(task):\n", + " return Result(host=task.host, result=\"Something went wrong\", exception=Exception())\n", + "\n", + "\n", + "def task_without_exception(task):\n", + " return \"All is fine\"\n", + "\n", + "def task(task):\n", + " task.run(task=task_with_exception)\n", + " task.run(task=task_without_exception)\n", + " return \"What's happening?\"\n", + "\n", + " \n", + "result_with_exception = nr.run(task=task)\n", + "\n", + "diff = write_result(result_with_exception, filename=\"out_files/write_result/result.txt\")" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "85ecda49", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "---- dev1.group_1: task ** changed : False ------------------------------------- INFO\n", + "\n", + "What's happening?\n", + "\n", + "---- dev1.group_1: task_with_exception ** changed : False ---------------------- INFO\n", + "\n", + "Something went wrong\n", + "\n", + "---- dev1.group_1: task_without_exception ** changed : False ------------------- INFO\n", + "\n", + "All is fine\n", + "\n", + "---- dev2.group_1: task ** changed : False ------------------------------------- INFO\n", + "\n", + "What's happening?\n", + "\n", + "---- dev2.group_1: task_with_exception ** changed : False ---------------------- INFO\n", + "\n", + "Something went wrong\n", + "\n", + "---- dev2.group_1: task_without_exception ** changed : False ------------------- INFO\n", + "\n", + "All is fine\n", + "\n", + "---- dev3.group_2: task ** changed : False ------------------------------------- INFO\n", + "\n", + "What's happening?\n", + "\n", + "---- dev3.group_2: task_with_exception ** changed : False ---------------------- INFO\n", + "\n", + "Something went wrong\n", + "\n", + "---- dev3.group_2: task_without_exception ** changed : False ------------------- INFO\n", + "\n", + "All is fine\n", + "\n", + "---- dev4.group_2: task ** changed : False ------------------------------------- INFO\n", + "\n", + "What's happening?\n", + "\n", + "---- dev4.group_2: task_with_exception ** changed : False ---------------------- INFO\n", + "\n", + "Something went wrong\n", + "\n", + "---- dev4.group_2: task_without_exception ** changed : False ------------------- INFO\n", + "\n", + "All is fine\n", + "\n", + "---- dev5.no_group: task ** changed : False ------------------------------------ INFO\n", + "\n", + "What's happening?\n", + "\n", + "---- dev5.no_group: task_with_exception ** changed : False --------------------- INFO\n", + "\n", + "Something went wrong\n", + "\n", + "---- dev5.no_group: task_without_exception ** changed : False ------------------ INFO\n", + "\n", + "All is fine\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m" + ] + } + ], + "source": [ + "cat out_files/write_result/result.txt" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "4cdc3d01", + "metadata": {}, + "outputs": [], + "source": [ + "diff = write_result(result_with_exception, filename=\"out_files/write_result/result.txt\", no_errors=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "391948d1", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "---- dev1.group_1: task ** changed : False ------------------------------------- INFO\n", + "\n", + "What's happening?\n", + "\n", + "---- dev1.group_1: task_without_exception ** changed : False ------------------- INFO\n", + "\n", + "All is fine\n", + "\n", + "---- dev2.group_1: task ** changed : False ------------------------------------- INFO\n", + "\n", + "What's happening?\n", + "\n", + "---- dev2.group_1: task_without_exception ** changed : False ------------------- INFO\n", + "\n", + "All is fine\n", + "\n", + "---- dev3.group_2: task ** changed : False ------------------------------------- INFO\n", + "\n", + "What's happening?\n", + "\n", + "---- dev3.group_2: task_without_exception ** changed : False ------------------- INFO\n", + "\n", + "All is fine\n", + "\n", + "---- dev4.group_2: task ** changed : False ------------------------------------- INFO\n", + "\n", + "What's happening?\n", + "\n", + "---- dev4.group_2: task_without_exception ** changed : False ------------------- INFO\n", + "\n", + "All is fine\n", + "\n", + "---- dev5.no_group: task ** changed : False ------------------------------------ INFO\n", + "\n", + "What's happening?\n", + "\n", + "---- dev5.no_group: task_without_exception ** changed : False ------------------ INFO\n", + "\n", + "All is fine\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m" + ] + } + ], + "source": [ + "cat out_files/write_result/result.txt" + ] + }, + { + "cell_type": "markdown", + "id": "0049ecb1", + "metadata": {}, + "source": [ + "## Count\n", + "\n", + "You can limit the number of results written to the file:" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "fe6abf02", + "metadata": {}, + "outputs": [], + "source": [ + "diff = write_result(result_with_exception, filename=\"out_files/write_result/result.txt\", count=2)" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "1a30deff", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "---- dev1.group_1: task ** changed : False ------------------------------------- INFO\n", + "\n", + "What's happening?\n", + "\n", + "---- dev1.group_1: task_with_exception ** changed : False ---------------------- INFO\n", + "\n", + "Something went wrong\n", + "\n", + "---- dev1.group_1: task_without_exception ** changed : False ------------------- INFO\n", + "\n", + "All is fine\n", + "\n", + "---- dev2.group_1: task ** changed : False ------------------------------------- INFO\n", + "\n", + "What's happening?\n", + "\n", + "---- dev2.group_1: task_with_exception ** changed : False ---------------------- INFO\n", + "\n", + "Something went wrong\n", + "\n", + "---- dev2.group_1: task_without_exception ** changed : False ------------------- INFO\n", + "\n", + "All is fine\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m" + ] + } + ], + "source": [ + "cat out_files/write_result/result.txt" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "03247361", + "metadata": {}, + "outputs": [], + "source": [ + "diff = write_result(result_with_exception, filename=\"out_files/write_result/result.txt\", count=-3)" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "9ed1c9ee", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "---- dev3.group_2: task ** changed : False ------------------------------------- INFO\n", + "\n", + "What's happening?\n", + "\n", + "---- dev3.group_2: task_with_exception ** changed : False ---------------------- INFO\n", + "\n", + "Something went wrong\n", + "\n", + "---- dev3.group_2: task_without_exception ** changed : False ------------------- INFO\n", + "\n", + "All is fine\n", + "\n", + "---- dev4.group_2: task ** changed : False ------------------------------------- INFO\n", + "\n", + "What's happening?\n", + "\n", + "---- dev4.group_2: task_with_exception ** changed : False ---------------------- INFO\n", + "\n", + "Something went wrong\n", + "\n", + "---- dev4.group_2: task_without_exception ** changed : False ------------------- INFO\n", + "\n", + "All is fine\n", + "\n", + "---- dev5.no_group: task ** changed : False ------------------------------------ INFO\n", + "\n", + "What's happening?\n", + "\n", + "---- dev5.no_group: task_with_exception ** changed : False --------------------- INFO\n", + "\n", + "Something went wrong\n", + "\n", + "---- dev5.no_group: task_without_exception ** changed : False ------------------ INFO\n", + "\n", + "All is fine\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m" + ] + } + ], + "source": [ + "cat out_files/write_result/result.txt" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/source/tutorials/function_write_results.ipynb b/docs/source/tutorials/function_write_results.ipynb new file mode 100644 index 0000000..eba9854 --- /dev/null +++ b/docs/source/tutorials/function_write_results.ipynb @@ -0,0 +1,1117 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "2d2c17c5", + "metadata": {}, + "source": [ + "# functions: write_results\n", + "\n", + "[write_results](../api/functions.rst#nornir_utils.plugins.functions.write_results) is a function that writes result to files with hostname names and returns list of tuples with hostname + diff between old file and new file:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "03a00337", + "metadata": {}, + "outputs": [], + "source": [ + "from nornir import InitNornir\n", + "\n", + "def dummy_task(task):\n", + " return \"hi!!!\"\n", + "\n", + "nr = InitNornir(\n", + " inventory={\n", + " \"plugin\":\"YAMLInventory\",\n", + " \"options\": {\n", + " \"host_file\": \"data/hosts.yaml\",\n", + " \"group_file\": \"data/groups.yaml\",\n", + " \"defaults_file\": \"data/defaults.yaml\",\n", + " }\n", + " }\n", + ")\n", + "\n", + "result = nr.run(task=dummy_task)" + ] + }, + { + "cell_type": "markdown", + "id": "57e43930", + "metadata": {}, + "source": [ + "Now we could write the results easily with the `write_results` function:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "cb99b478", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[('dev1.group_1',\n", + " '--- out_files/write_results/dev1.group_1\\n\\n+++ new\\n\\n@@ -0,0 +1,3 @@\\n\\n+---- dev1.group_1: dummy_task ** changed : False ------------------------------- INFO\\n+\\n+hi!!!'),\n", + " ('dev2.group_1',\n", + " '--- out_files/write_results/dev2.group_1\\n\\n+++ new\\n\\n@@ -0,0 +1,3 @@\\n\\n+---- dev2.group_1: dummy_task ** changed : False ------------------------------- INFO\\n+\\n+hi!!!'),\n", + " ('dev3.group_2',\n", + " '--- out_files/write_results/dev3.group_2\\n\\n+++ new\\n\\n@@ -0,0 +1,3 @@\\n\\n+---- dev3.group_2: dummy_task ** changed : False ------------------------------- INFO\\n+\\n+hi!!!'),\n", + " ('dev4.group_2',\n", + " '--- out_files/write_results/dev4.group_2\\n\\n+++ new\\n\\n@@ -0,0 +1,3 @@\\n\\n+---- dev4.group_2: dummy_task ** changed : False ------------------------------- INFO\\n+\\n+hi!!!'),\n", + " ('dev5.no_group',\n", + " '--- out_files/write_results/dev5.no_group\\n\\n+++ new\\n\\n@@ -0,0 +1,3 @@\\n\\n+---- dev5.no_group: dummy_task ** changed : False ------------------------------ INFO\\n+\\n+hi!!!')]" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from nornir_utils.plugins.functions import write_results\n", + "\n", + "write_results(result, dirname=\"out_files/write_results\")" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "cb90732d", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "dev1.group_1 dev2.group_1 dev3.group_2 dev4.group_2\tdev5.no_group\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m" + ] + } + ], + "source": [ + "!ls out_files/write_results" + ] + }, + { + "cell_type": "markdown", + "id": "942776f1", + "metadata": {}, + "source": [ + "Let's look at the content of each file with one bash command:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "5227fd1e", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[1mout_files/write_results/dev1.group_1\u001b[0m\n", + "---- dev1.group_1: dummy_task ** changed : False ------------------------------- INFO\n", + "\n", + "hi!!!\n", + "\n", + "\u001b[1mout_files/write_results/dev2.group_1\u001b[0m\n", + "---- dev2.group_1: dummy_task ** changed : False ------------------------------- INFO\n", + "\n", + "hi!!!\n", + "\n", + "\u001b[1mout_files/write_results/dev3.group_2\u001b[0m\n", + "---- dev3.group_2: dummy_task ** changed : False ------------------------------- INFO\n", + "\n", + "hi!!!\n", + "\n", + "\u001b[1mout_files/write_results/dev4.group_2\u001b[0m\n", + "---- dev4.group_2: dummy_task ** changed : False ------------------------------- INFO\n", + "\n", + "hi!!!\n", + "\n", + "\u001b[1mout_files/write_results/dev5.no_group\u001b[0m\n", + "---- dev5.no_group: dummy_task ** changed : False ------------------------------ INFO\n", + "\n", + "hi!!!\n", + "\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m" + ] + } + ], + "source": [ + "!for f in out_files/write_results/*; do (echo -e \"\\033[1m${f}\\033[0m\"; cat \"${f}\"; echo $'\\n'); done" + ] + }, + { + "cell_type": "markdown", + "id": "a1f86c3a", + "metadata": {}, + "source": [ + "`dirname` here is path to directory, you want to write the results for each host. `write_results` creates directories from the path, if it's necessary." + ] + }, + { + "cell_type": "markdown", + "id": "c47e072f", + "metadata": {}, + "source": [ + "## Diff\n", + "\n", + "As you can see, `write_results` returns list of tiples with hostname + diff between the previous and current file state:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "14c221c4", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[('dev1.group_1', '--- out_files/write_results/dev1.group_1\\n\\n+++ new\\n\\n@@ -0,0 +1,3 @@\\n\\n+---- dev1.group_1: smart_task ** changed : False ------------------------------- INFO\\n+\\n+hihi!!!'), ('dev2.group_1', '--- out_files/write_results/dev2.group_1\\n\\n+++ new\\n\\n@@ -0,0 +1,3 @@\\n\\n+---- dev2.group_1: smart_task ** changed : False ------------------------------- INFO\\n+\\n+hihi!!!'), ('dev3.group_2', '--- out_files/write_results/dev3.group_2\\n\\n+++ new\\n\\n@@ -0,0 +1,3 @@\\n\\n+---- dev3.group_2: smart_task ** changed : False ------------------------------- INFO\\n+\\n+hihi!!!'), ('dev4.group_2', '--- out_files/write_results/dev4.group_2\\n\\n+++ new\\n\\n@@ -0,0 +1,3 @@\\n\\n+---- dev4.group_2: smart_task ** changed : False ------------------------------- INFO\\n+\\n+hihi!!!'), ('dev5.no_group', '--- out_files/write_results/dev5.no_group\\n\\n+++ new\\n\\n@@ -0,0 +1,3 @@\\n\\n+---- dev5.no_group: smart_task ** changed : False ------------------------------ INFO\\n+\\n+hihi!!!')]\u001b[0m\u001b[0m\u001b[0m\n", + "\u001b[0m\u001b[0m\u001b[0m" + ] + } + ], + "source": [ + "def smart_task(task):\n", + " return \"hihi!!!\"\n", + "\n", + "result = nr.run(task=smart_task)\n", + "\n", + "print(write_results(result, dirname=\"out_files/write_results\"))" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "d234c3c3", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[1mout_files/write_results/dev1.group_1\u001b[0m\n", + "---- dev1.group_1: smart_task ** changed : False ------------------------------- INFO\n", + "\n", + "hihi!!!\n", + "\n", + "\u001b[1mout_files/write_results/dev2.group_1\u001b[0m\n", + "---- dev2.group_1: smart_task ** changed : False ------------------------------- INFO\n", + "\n", + "hihi!!!\n", + "\n", + "\u001b[1mout_files/write_results/dev3.group_2\u001b[0m\n", + "---- dev3.group_2: smart_task ** changed : False ------------------------------- INFO\n", + "\n", + "hihi!!!\n", + "\n", + "\u001b[1mout_files/write_results/dev4.group_2\u001b[0m\n", + "---- dev4.group_2: smart_task ** changed : False ------------------------------- INFO\n", + "\n", + "hihi!!!\n", + "\n", + "\u001b[1mout_files/write_results/dev5.no_group\u001b[0m\n", + "---- dev5.no_group: smart_task ** changed : False ------------------------------ INFO\n", + "\n", + "hihi!!!\n", + "\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m" + ] + } + ], + "source": [ + "!for f in out_files/write_results/*; do (echo -e \"\\033[1m${f}\\033[0m\"; cat \"${f}\"; echo $'\\n'); done" + ] + }, + { + "cell_type": "markdown", + "id": "231ce6f0", + "metadata": {}, + "source": [ + "## Writing specific data\n", + "\n", + "If the task returns different information, you can also select which ones to write. For instance:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "774eaef7", + "metadata": {}, + "outputs": [], + "source": [ + "from nornir.core.task import Result\n", + "\n", + "def task_with_data(task):\n", + " return Result(host=task.host, result=\"Spaghetti monster\", sw_char=\"Jar Jar Binks\", food=\"hawaiian pizza\", OS=\"windows\")\n", + "\n", + "\n", + "fav_result = nr.run(task=task_with_data)\n", + "\n", + "# write only sw_char, food vars and write diff to diff variable \n", + "diffs = write_results(fav_result, dirname=\"out_files/write_results\", vars=[\"sw_char\", \"food\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "a1ac0f7f", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[1mout_files/write_results/dev1.group_1\u001b[0m\n", + "---- dev1.group_1: task_with_data ** changed : False --------------------------- INFO\n", + "\n", + "Jar Jar Binks\n", + "\n", + "hawaiian pizza\n", + "\n", + "\u001b[1mout_files/write_results/dev2.group_1\u001b[0m\n", + "---- dev2.group_1: task_with_data ** changed : False --------------------------- INFO\n", + "\n", + "Jar Jar Binks\n", + "\n", + "hawaiian pizza\n", + "\n", + "\u001b[1mout_files/write_results/dev3.group_2\u001b[0m\n", + "---- dev3.group_2: task_with_data ** changed : False --------------------------- INFO\n", + "\n", + "Jar Jar Binks\n", + "\n", + "hawaiian pizza\n", + "\n", + "\u001b[1mout_files/write_results/dev4.group_2\u001b[0m\n", + "---- dev4.group_2: task_with_data ** changed : False --------------------------- INFO\n", + "\n", + "Jar Jar Binks\n", + "\n", + "hawaiian pizza\n", + "\n", + "\u001b[1mout_files/write_results/dev5.no_group\u001b[0m\n", + "---- dev5.no_group: task_with_data ** changed : False -------------------------- INFO\n", + "\n", + "Jar Jar Binks\n", + "\n", + "hawaiian pizza\n", + "\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m" + ] + } + ], + "source": [ + "!for f in out_files/write_results/*; do (echo -e \"\\033[1m${f}\\033[0m\"; cat \"${f}\"; echo $'\\n'); done" + ] + }, + { + "cell_type": "markdown", + "id": "568719c8", + "metadata": {}, + "source": [ + "## Severity\n", + "\n", + "You can also ask `write_results` to write the results only if the severity is equal or superior to the one specified. This is particularly useful if your script is very large and you don't care about intermediate results. For instance:" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "6dd24ac3", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "AggregatedResult (complex_task): {'dev1.group_1': MultiResult: [Result: \"complex_task\", Result: \"dummy_task\", Result: \"dummy_task\", Result: \"dummy_task\", Result: \"dummy_task\", Result: \"dummy_task\"], 'dev2.group_1': MultiResult: [Result: \"complex_task\", Result: \"dummy_task\", Result: \"dummy_task\", Result: \"dummy_task\", Result: \"dummy_task\", Result: \"dummy_task\"], 'dev3.group_2': MultiResult: [Result: \"complex_task\", Result: \"dummy_task\", Result: \"dummy_task\", Result: \"dummy_task\", Result: \"dummy_task\", Result: \"dummy_task\"], 'dev4.group_2': MultiResult: [Result: \"complex_task\", Result: \"dummy_task\", Result: \"dummy_task\", Result: \"dummy_task\", Result: \"dummy_task\", Result: \"dummy_task\"], 'dev5.no_group': MultiResult: [Result: \"complex_task\", Result: \"dummy_task\", Result: \"dummy_task\", Result: \"dummy_task\", Result: \"dummy_task\", Result: \"dummy_task\"]}" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import logging\n", + "\n", + "def complex_task(task):\n", + " task.run(task=dummy_task, severity_level=logging.DEBUG)\n", + " task.run(task=dummy_task, severity_level=logging.DEBUG)\n", + " task.run(task=dummy_task, severity_level=logging.DEBUG)\n", + " task.run(task=dummy_task, severity_level=logging.DEBUG)\n", + " task.run(task=dummy_task, severity_level=logging.DEBUG)\n", + " return \"I did a lot of things!!!\"\n", + "\n", + "complex_result = nr.run(task=complex_task)\n", + "complex_result" + ] + }, + { + "cell_type": "markdown", + "id": "36d6d9c4", + "metadata": {}, + "source": [ + "`write_results` will only write `INFO` severity and above by default so if we write the result we should only see the result of the parent task:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "9d33d258", + "metadata": {}, + "outputs": [], + "source": [ + "diffs = write_results(complex_result, dirname=\"out_files/write_results\")" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "36f7b1c9", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[1mout_files/write_results/dev1.group_1\u001b[0m\n", + "---- dev1.group_1: complex_task ** changed : False ----------------------------- INFO\n", + "\n", + "I did a lot of things!!!\n", + "\n", + "\u001b[1mout_files/write_results/dev2.group_1\u001b[0m\n", + "---- dev2.group_1: complex_task ** changed : False ----------------------------- INFO\n", + "\n", + "I did a lot of things!!!\n", + "\n", + "\u001b[1mout_files/write_results/dev3.group_2\u001b[0m\n", + "---- dev3.group_2: complex_task ** changed : False ----------------------------- INFO\n", + "\n", + "I did a lot of things!!!\n", + "\n", + "\u001b[1mout_files/write_results/dev4.group_2\u001b[0m\n", + "---- dev4.group_2: complex_task ** changed : False ----------------------------- INFO\n", + "\n", + "I did a lot of things!!!\n", + "\n", + "\u001b[1mout_files/write_results/dev5.no_group\u001b[0m\n", + "---- dev5.no_group: complex_task ** changed : False ---------------------------- INFO\n", + "\n", + "I did a lot of things!!!\n", + "\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m" + ] + } + ], + "source": [ + "!for f in out_files/write_results/*; do (echo -e \"\\033[1m${f}\\033[0m\"; cat \"${f}\"; echo $'\\n'); done" + ] + }, + { + "cell_type": "markdown", + "id": "86998af3", + "metadata": {}, + "source": [ + "If you wanted to write all the tasks for debugging purposes you could specify it with:" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "f9c380ae", + "metadata": {}, + "outputs": [], + "source": [ + "diffs = write_results(complex_result, dirname=\"out_files/write_results\", severity_level=logging.DEBUG)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "3801974b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[1mout_files/write_results/dev1.group_1\u001b[0m\n", + "---- dev1.group_1: complex_task ** changed : False ----------------------------- INFO\n", + "\n", + "I did a lot of things!!!\n", + "\n", + "---- dev1.group_1: dummy_task ** changed : False ------------------------------- DEBUG\n", + "\n", + "hi!!!\n", + "\n", + "---- dev1.group_1: dummy_task ** changed : False ------------------------------- DEBUG\n", + "\n", + "hi!!!\n", + "\n", + "---- dev1.group_1: dummy_task ** changed : False ------------------------------- DEBUG\n", + "\n", + "hi!!!\n", + "\n", + "---- dev1.group_1: dummy_task ** changed : False ------------------------------- DEBUG\n", + "\n", + "hi!!!\n", + "\n", + "---- dev1.group_1: dummy_task ** changed : False ------------------------------- DEBUG\n", + "\n", + "hi!!!\n", + "\n", + "\u001b[1mout_files/write_results/dev2.group_1\u001b[0m\n", + "---- dev2.group_1: complex_task ** changed : False ----------------------------- INFO\n", + "\n", + "I did a lot of things!!!\n", + "\n", + "---- dev2.group_1: dummy_task ** changed : False ------------------------------- DEBUG\n", + "\n", + "hi!!!\n", + "\n", + "---- dev2.group_1: dummy_task ** changed : False ------------------------------- DEBUG\n", + "\n", + "hi!!!\n", + "\n", + "---- dev2.group_1: dummy_task ** changed : False ------------------------------- DEBUG\n", + "\n", + "hi!!!\n", + "\n", + "---- dev2.group_1: dummy_task ** changed : False ------------------------------- DEBUG\n", + "\n", + "hi!!!\n", + "\n", + "---- dev2.group_1: dummy_task ** changed : False ------------------------------- DEBUG\n", + "\n", + "hi!!!\n", + "\n", + "\u001b[1mout_files/write_results/dev3.group_2\u001b[0m\n", + "---- dev3.group_2: complex_task ** changed : False ----------------------------- INFO\n", + "\n", + "I did a lot of things!!!\n", + "\n", + "---- dev3.group_2: dummy_task ** changed : False ------------------------------- DEBUG\n", + "\n", + "hi!!!\n", + "\n", + "---- dev3.group_2: dummy_task ** changed : False ------------------------------- DEBUG\n", + "\n", + "hi!!!\n", + "\n", + "---- dev3.group_2: dummy_task ** changed : False ------------------------------- DEBUG\n", + "\n", + "hi!!!\n", + "\n", + "---- dev3.group_2: dummy_task ** changed : False ------------------------------- DEBUG\n", + "\n", + "hi!!!\n", + "\n", + "---- dev3.group_2: dummy_task ** changed : False ------------------------------- DEBUG\n", + "\n", + "hi!!!\n", + "\n", + "\u001b[1mout_files/write_results/dev4.group_2\u001b[0m\n", + "---- dev4.group_2: complex_task ** changed : False ----------------------------- INFO\n", + "\n", + "I did a lot of things!!!\n", + "\n", + "---- dev4.group_2: dummy_task ** changed : False ------------------------------- DEBUG\n", + "\n", + "hi!!!\n", + "\n", + "---- dev4.group_2: dummy_task ** changed : False ------------------------------- DEBUG\n", + "\n", + "hi!!!\n", + "\n", + "---- dev4.group_2: dummy_task ** changed : False ------------------------------- DEBUG\n", + "\n", + "hi!!!\n", + "\n", + "---- dev4.group_2: dummy_task ** changed : False ------------------------------- DEBUG\n", + "\n", + "hi!!!\n", + "\n", + "---- dev4.group_2: dummy_task ** changed : False ------------------------------- DEBUG\n", + "\n", + "hi!!!\n", + "\n", + "\u001b[1mout_files/write_results/dev5.no_group\u001b[0m\n", + "---- dev5.no_group: complex_task ** changed : False ---------------------------- INFO\n", + "\n", + "I did a lot of things!!!\n", + "\n", + "---- dev5.no_group: dummy_task ** changed : False ------------------------------ DEBUG\n", + "\n", + "hi!!!\n", + "\n", + "---- dev5.no_group: dummy_task ** changed : False ------------------------------ DEBUG\n", + "\n", + "hi!!!\n", + "\n", + "---- dev5.no_group: dummy_task ** changed : False ------------------------------ DEBUG\n", + "\n", + "hi!!!\n", + "\n", + "---- dev5.no_group: dummy_task ** changed : False ------------------------------ DEBUG\n", + "\n", + "hi!!!\n", + "\n", + "---- dev5.no_group: dummy_task ** changed : False ------------------------------ DEBUG\n", + "\n", + "hi!!!\n", + "\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m" + ] + } + ], + "source": [ + "!for f in out_files/write_results/*; do (echo -e \"\\033[1m${f}\\033[0m\"; cat \"${f}\"; echo $'\\n'); done" + ] + }, + { + "cell_type": "markdown", + "id": "44d096ef", + "metadata": {}, + "source": [ + "## Write host\n", + "\n", + "`write_host` argument can help you, if you don't need to write hostnames to files:" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "fb93e599", + "metadata": {}, + "outputs": [], + "source": [ + "diff = write_results(result, dirname=\"out_files/write_results\", write_host=False)" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "1675db9a", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[1mout_files/write_results/dev1.group_1\u001b[0m\n", + "---- smart_task ** changed : False --------------------------------------------- INFO\n", + "\n", + "hihi!!!\n", + "\n", + "\u001b[1mout_files/write_results/dev2.group_1\u001b[0m\n", + "---- smart_task ** changed : False --------------------------------------------- INFO\n", + "\n", + "hihi!!!\n", + "\n", + "\u001b[1mout_files/write_results/dev3.group_2\u001b[0m\n", + "---- smart_task ** changed : False --------------------------------------------- INFO\n", + "\n", + "hihi!!!\n", + "\n", + "\u001b[1mout_files/write_results/dev4.group_2\u001b[0m\n", + "---- smart_task ** changed : False --------------------------------------------- INFO\n", + "\n", + "hihi!!!\n", + "\n", + "\u001b[1mout_files/write_results/dev5.no_group\u001b[0m\n", + "---- smart_task ** changed : False --------------------------------------------- INFO\n", + "\n", + "hihi!!!\n", + "\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m" + ] + } + ], + "source": [ + "!for f in out_files/write_results/*; do (echo -e \"\\033[1m${f}\\033[0m\"; cat \"${f}\"; echo $'\\n'); done" + ] + }, + { + "cell_type": "markdown", + "id": "34a824f1", + "metadata": {}, + "source": [ + "## Append\n", + "\n", + "`append` argument allows you to use `a+` or `w+` (default mode) writing mode. As instance:" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "62cbce4a", + "metadata": {}, + "outputs": [], + "source": [ + "diffs = write_results(fav_result, dirname=\"out_files/write_results\", append=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "77bfdfba", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[1mout_files/write_results/dev1.group_1\u001b[0m\n", + "---- smart_task ** changed : False --------------------------------------------- INFO\n", + "\n", + "hihi!!!\n", + "\n", + "---- dev1.group_1: task_with_data ** changed : False --------------------------- INFO\n", + "\n", + "Spaghetti monster\n", + "\n", + "\u001b[1mout_files/write_results/dev2.group_1\u001b[0m\n", + "---- smart_task ** changed : False --------------------------------------------- INFO\n", + "\n", + "hihi!!!\n", + "\n", + "---- dev2.group_1: task_with_data ** changed : False --------------------------- INFO\n", + "\n", + "Spaghetti monster\n", + "\n", + "\u001b[1mout_files/write_results/dev3.group_2\u001b[0m\n", + "---- smart_task ** changed : False --------------------------------------------- INFO\n", + "\n", + "hihi!!!\n", + "\n", + "---- dev3.group_2: task_with_data ** changed : False --------------------------- INFO\n", + "\n", + "Spaghetti monster\n", + "\n", + "\u001b[1mout_files/write_results/dev4.group_2\u001b[0m\n", + "---- smart_task ** changed : False --------------------------------------------- INFO\n", + "\n", + "hihi!!!\n", + "\n", + "---- dev4.group_2: task_with_data ** changed : False --------------------------- INFO\n", + "\n", + "Spaghetti monster\n", + "\n", + "\u001b[1mout_files/write_results/dev5.no_group\u001b[0m\n", + "---- smart_task ** changed : False --------------------------------------------- INFO\n", + "\n", + "hihi!!!\n", + "\n", + "---- dev5.no_group: task_with_data ** changed : False -------------------------- INFO\n", + "\n", + "Spaghetti monster\n", + "\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m" + ] + } + ], + "source": [ + "!for f in out_files/write_results/*; do (echo -e \"\\033[1m${f}\\033[0m\"; cat \"${f}\"; echo $'\\n'); done" + ] + }, + { + "cell_type": "markdown", + "id": "57f5b76d", + "metadata": {}, + "source": [ + "# No errors\n", + "\n", + "Don't write errors to files with `no_errors` argument. As instance:" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "c9d3a814", + "metadata": {}, + "outputs": [], + "source": [ + "def task_with_exception(task):\n", + " return Result(host=task.host, result=\"Something went wrong\", exception=Exception())\n", + "\n", + "\n", + "def task_without_exception(task):\n", + " return \"All is fine\"\n", + "\n", + "def task(task):\n", + " task.run(task=task_with_exception)\n", + " task.run(task=task_without_exception)\n", + " return \"What's happening?\"\n", + "\n", + " \n", + "result_with_exception = nr.run(task=task)\n", + "\n", + "diffs = write_results(result_with_exception, dirname=\"out_files/write_results\")" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "85ecda49", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[1mout_files/write_results/dev1.group_1\u001b[0m\n", + "---- dev1.group_1: task ** changed : False ------------------------------------- INFO\n", + "\n", + "What's happening?\n", + "\n", + "---- dev1.group_1: task_with_exception ** changed : False ---------------------- INFO\n", + "\n", + "Something went wrong\n", + "\n", + "---- dev1.group_1: task_without_exception ** changed : False ------------------- INFO\n", + "\n", + "All is fine\n", + "\n", + "\u001b[1mout_files/write_results/dev2.group_1\u001b[0m\n", + "---- dev2.group_1: task ** changed : False ------------------------------------- INFO\n", + "\n", + "What's happening?\n", + "\n", + "---- dev2.group_1: task_with_exception ** changed : False ---------------------- INFO\n", + "\n", + "Something went wrong\n", + "\n", + "---- dev2.group_1: task_without_exception ** changed : False ------------------- INFO\n", + "\n", + "All is fine\n", + "\n", + "\u001b[1mout_files/write_results/dev3.group_2\u001b[0m\n", + "---- dev3.group_2: task ** changed : False ------------------------------------- INFO\n", + "\n", + "What's happening?\n", + "\n", + "---- dev3.group_2: task_with_exception ** changed : False ---------------------- INFO\n", + "\n", + "Something went wrong\n", + "\n", + "---- dev3.group_2: task_without_exception ** changed : False ------------------- INFO\n", + "\n", + "All is fine\n", + "\n", + "\u001b[1mout_files/write_results/dev4.group_2\u001b[0m\n", + "---- dev4.group_2: task ** changed : False ------------------------------------- INFO\n", + "\n", + "What's happening?\n", + "\n", + "---- dev4.group_2: task_with_exception ** changed : False ---------------------- INFO\n", + "\n", + "Something went wrong\n", + "\n", + "---- dev4.group_2: task_without_exception ** changed : False ------------------- INFO\n", + "\n", + "All is fine\n", + "\n", + "\u001b[1mout_files/write_results/dev5.no_group\u001b[0m\n", + "---- dev5.no_group: task ** changed : False ------------------------------------ INFO\n", + "\n", + "What's happening?\n", + "\n", + "---- dev5.no_group: task_with_exception ** changed : False --------------------- INFO\n", + "\n", + "Something went wrong\n", + "\n", + "---- dev5.no_group: task_without_exception ** changed : False ------------------ INFO\n", + "\n", + "All is fine\n", + "\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m" + ] + } + ], + "source": [ + "!for f in out_files/write_results/*; do (echo -e \"\\033[1m${f}\\033[0m\"; cat \"${f}\"; echo $'\\n'); done" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "4cdc3d01", + "metadata": {}, + "outputs": [], + "source": [ + "diffs = write_results(result_with_exception, dirname=\"out_files/write_results\", no_errors=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "391948d1", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[1mout_files/write_results/dev1.group_1\u001b[0m\n", + "---- dev1.group_1: task ** changed : False ------------------------------------- INFO\n", + "\n", + "What's happening?\n", + "\n", + "---- dev1.group_1: task_without_exception ** changed : False ------------------- INFO\n", + "\n", + "All is fine\n", + "\n", + "\u001b[1mout_files/write_results/dev2.group_1\u001b[0m\n", + "---- dev2.group_1: task ** changed : False ------------------------------------- INFO\n", + "\n", + "What's happening?\n", + "\n", + "---- dev2.group_1: task_without_exception ** changed : False ------------------- INFO\n", + "\n", + "All is fine\n", + "\n", + "\u001b[1mout_files/write_results/dev3.group_2\u001b[0m\n", + "---- dev3.group_2: task ** changed : False ------------------------------------- INFO\n", + "\n", + "What's happening?\n", + "\n", + "---- dev3.group_2: task_without_exception ** changed : False ------------------- INFO\n", + "\n", + "All is fine\n", + "\n", + "\u001b[1mout_files/write_results/dev4.group_2\u001b[0m\n", + "---- dev4.group_2: task ** changed : False ------------------------------------- INFO\n", + "\n", + "What's happening?\n", + "\n", + "---- dev4.group_2: task_without_exception ** changed : False ------------------- INFO\n", + "\n", + "All is fine\n", + "\n", + "\u001b[1mout_files/write_results/dev5.no_group\u001b[0m\n", + "---- dev5.no_group: task ** changed : False ------------------------------------ INFO\n", + "\n", + "What's happening?\n", + "\n", + "---- dev5.no_group: task_without_exception ** changed : False ------------------ INFO\n", + "\n", + "All is fine\n", + "\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m" + ] + } + ], + "source": [ + "!for f in out_files/write_results/*; do (echo -e \"\\033[1m${f}\\033[0m\"; cat \"${f}\"; echo $'\\n'); done" + ] + }, + { + "cell_type": "markdown", + "id": "0049ecb1", + "metadata": {}, + "source": [ + "## Count\n", + "\n", + "You can limit the number of files with results.\n", + "As instance, sort the results list by hostname, collect all the results for 2 first hosts and write them to files:" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "35330087", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m" + ] + } + ], + "source": [ + "# clear out_files directory, at first\n", + "!rm -r out_files/write_results/*" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "fe6abf02", + "metadata": {}, + "outputs": [], + "source": [ + "diffs = write_results(result_with_exception, dirname=\"out_files/write_results\", count=2)" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "1a30deff", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[1mout_files/write_results/dev1.group_1\u001b[0m\n", + "---- dev1.group_1: task ** changed : False ------------------------------------- INFO\n", + "\n", + "What's happening?\n", + "\n", + "---- dev1.group_1: task_with_exception ** changed : False ---------------------- INFO\n", + "\n", + "Something went wrong\n", + "\n", + "---- dev1.group_1: task_without_exception ** changed : False ------------------- INFO\n", + "\n", + "All is fine\n", + "\n", + "\u001b[1mout_files/write_results/dev2.group_1\u001b[0m\n", + "---- dev2.group_1: task ** changed : False ------------------------------------- INFO\n", + "\n", + "What's happening?\n", + "\n", + "---- dev2.group_1: task_with_exception ** changed : False ---------------------- INFO\n", + "\n", + "Something went wrong\n", + "\n", + "---- dev2.group_1: task_without_exception ** changed : False ------------------- INFO\n", + "\n", + "All is fine\n", + "\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m" + ] + } + ], + "source": [ + "!for f in out_files/write_results/*; do (echo -e \"\\033[1m${f}\\033[0m\"; cat \"${f}\"; echo $'\\n'); done" + ] + }, + { + "cell_type": "markdown", + "id": "f8c29f91", + "metadata": {}, + "source": [ + "As instance, sort the results list by hostname, collect all the results for 3 last hosts and write them to files:" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "e7782e55", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m" + ] + } + ], + "source": [ + "# clear out_files directory, at first\n", + "!rm -r out_files/write_results/*; " + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "03247361", + "metadata": {}, + "outputs": [], + "source": [ + "diffs = write_results(result_with_exception, dirname=\"out_files/write_results\", count=-3)" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "9ed1c9ee", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[1mout_files/write_results/dev3.group_2\u001b[0m\n", + "---- dev3.group_2: task ** changed : False ------------------------------------- INFO\n", + "\n", + "What's happening?\n", + "\n", + "---- dev3.group_2: task_with_exception ** changed : False ---------------------- INFO\n", + "\n", + "Something went wrong\n", + "\n", + "---- dev3.group_2: task_without_exception ** changed : False ------------------- INFO\n", + "\n", + "All is fine\n", + "\n", + "\u001b[1mout_files/write_results/dev4.group_2\u001b[0m\n", + "---- dev4.group_2: task ** changed : False ------------------------------------- INFO\n", + "\n", + "What's happening?\n", + "\n", + "---- dev4.group_2: task_with_exception ** changed : False ---------------------- INFO\n", + "\n", + "Something went wrong\n", + "\n", + "---- dev4.group_2: task_without_exception ** changed : False ------------------- INFO\n", + "\n", + "All is fine\n", + "\n", + "\u001b[1mout_files/write_results/dev5.no_group\u001b[0m\n", + "---- dev5.no_group: task ** changed : False ------------------------------------ INFO\n", + "\n", + "What's happening?\n", + "\n", + "---- dev5.no_group: task_with_exception ** changed : False --------------------- INFO\n", + "\n", + "Something went wrong\n", + "\n", + "---- dev5.no_group: task_without_exception ** changed : False ------------------ INFO\n", + "\n", + "All is fine\n", + "\n", + "\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m\u001b[0m" + ] + } + ], + "source": [ + "!for f in out_files/write_results/*; do (echo -e \"\\033[1m${f}\\033[0m\"; cat \"${f}\"; echo $'\\n'); done" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/nornir_utils/plugins/functions/__init__.py b/nornir_utils/plugins/functions/__init__.py index a2acbf4..da1bdd4 100644 --- a/nornir_utils/plugins/functions/__init__.py +++ b/nornir_utils/plugins/functions/__init__.py @@ -1,3 +1,16 @@ -from .print_result import print_result, print_title +from .print_result import ( + print_result, + print_title, +) -__all__ = ("print_result", "print_title") +from .print_stat import print_stat +from .write_result import write_result +from .write_results import write_results + +__all__ = ( + "print_result", + "print_title", + "print_stat", + "write_result", + "write_results", +) diff --git a/nornir_utils/plugins/functions/print_result.py b/nornir_utils/plugins/functions/print_result.py index df64f10..69e1421 100644 --- a/nornir_utils/plugins/functions/print_result.py +++ b/nornir_utils/plugins/functions/print_result.py @@ -1,7 +1,8 @@ import logging import pprint import threading -from typing import List, cast +from itertools import islice +from typing import List, cast, Optional, Dict, Any from collections import OrderedDict import json @@ -16,12 +17,31 @@ init(autoreset=True, strip=False) +def _slice_result( + result: AggregatedResult, + count: Optional[int] = None, +): + results: Dict[Any, Any] = dict(sorted(result.items())) + if isinstance(count, int): + length = len(results) + if count >= 0: + slice_length = [0, length and count] + elif (length + count) < 0: + slice_length = [0, length] + else: + slice_length = [length + count, length] + results = dict(islice(results.items(), *slice_length)) + return results + + def print_title(title: str) -> None: """ Helper function to print a title. """ msg = "**** {} ".format(title) - print("{}{}{}{}".format(Style.BRIGHT, Fore.GREEN, msg, "*" * (80 - len(msg)))) + print( + "{}{}{}{}".format(Style.BRIGHT, Fore.GREEN, msg, "*" * (80 - len(msg))) + ) def _get_color(result: Result, failed: bool) -> str: @@ -47,7 +67,9 @@ def _print_individual_result( color = _get_color(result, failed) subtitle = ( - "" if result.changed is None else " ** changed : {} ".format(result.changed) + "" + if result.changed is None + else " ** changed : {} ".format(result.changed) ) level_name = logging.getLevelName(result.severity_level) symbol = "v" if task_group else "-" @@ -82,6 +104,7 @@ def _print_result( failed: bool = False, severity_level: int = logging.INFO, print_host: bool = False, + count: Optional[int] = None, ) -> None: attrs = attrs or ["diff", "result", "stdout"] if isinstance(attrs, str): @@ -89,8 +112,13 @@ def _print_result( if isinstance(result, AggregatedResult): msg = result.name - print("{}{}{}{}".format(Style.BRIGHT, Fore.CYAN, msg, "*" * (80 - len(msg)))) - for host, host_data in sorted(result.items()): + msg = "{}{}{}{}".format( + Style.BRIGHT, Fore.CYAN, msg, "*" * (80 - len(msg)) + ) + if count != 0: + print(msg) + result = _slice_result(result, count) + for host, host_data in result.items(): title = ( "" if host_data.changed is None @@ -98,7 +126,9 @@ def _print_result( ) msg = "* {}{}".format(host, title) print( - "{}{}{}{}".format(Style.BRIGHT, Fore.BLUE, msg, "*" * (80 - len(msg))) + "{}{}{}{}".format( + Style.BRIGHT, Fore.BLUE, msg, "*" * (80 - len(msg)) + ) ) _print_result(host_data, attrs, failed, severity_level) elif isinstance(result, MultiResult): @@ -114,7 +144,9 @@ def _print_result( _print_result(r, attrs, failed, severity_level) color = _get_color(result[0], failed) msg = "^^^^ END {} ".format(result[0].name) - print("{}{}{}{}".format(Style.BRIGHT, color, msg, "^" * (80 - len(msg)))) + print( + "{}{}{}{}".format(Style.BRIGHT, color, msg, "^" * (80 - len(msg))) + ) elif isinstance(result, Result): _print_individual_result( result, attrs, failed, severity_level, print_host=print_host @@ -126,6 +158,7 @@ def print_result( vars: List[str] = None, failed: bool = False, severity_level: int = logging.INFO, + count: Optional[int] = None, ) -> None: """ Prints an object of type `nornir.core.task.Result` @@ -135,9 +168,19 @@ def print_result( vars: Which attributes you want to print failed: if ``True`` assume the task failed severity_level: Print only errors with this severity level or higher + count: Number of sorted results. It's acceptable + to use numbers with minus sign(-5, as an example), + then results will be from the end of results list """ LOCK.acquire() try: - _print_result(result, vars, failed, severity_level, print_host=True) + _print_result( + result, + vars, + failed=failed, + severity_level=severity_level, + print_host=True, + count=count, + ) finally: LOCK.release() diff --git a/nornir_utils/plugins/functions/print_stat.py b/nornir_utils/plugins/functions/print_stat.py new file mode 100644 index 0000000..f5b4992 --- /dev/null +++ b/nornir_utils/plugins/functions/print_stat.py @@ -0,0 +1,115 @@ +import threading +from typing import Optional, Tuple +from nornir_utils.plugins.functions.print_result import ( + _get_color, + _slice_result, +) + +from colorama import Fore, Style, init + +from nornir.core.task import AggregatedResult, MultiResult, Result + + +LOCK = threading.Lock() + + +init(autoreset=True, strip=False) + + +def _print_individual_stat( + result: Result, + res_sum: int = 0, + ch_sum: int = 0, + f_sum: int = 0, +) -> Tuple[int, int, int]: + + f, ch = (result.failed, result.changed) + + res_sum += 1 + ch_sum += int(ch) + f_sum += int(f) + + color = _get_color(result, f) + msg = "{:<35} ok={:<15} changed={:<15} failed={:<15}".format( + result.name, not f, ch, f + ) + print(" {}{}{}".format(Style.BRIGHT, color, msg)) + return res_sum, ch_sum, f_sum + + +def _print_stat( + result: Result, + count: Optional[int] = None, + res_sum: int = 0, + ch_sum: int = 0, + f_sum: int = 0, +) -> Tuple[int, int, int]: + + if isinstance(result, AggregatedResult): + msg = result.name + msg = "{}{}{}{}".format( + Style.BRIGHT, Fore.CYAN, msg, "*" * (80 - len(msg)) + ) + if count != 0: + print(msg) + result = _slice_result(result, count) + for host, host_data in result.items(): + msg_host = "* {} ".format(host) + print( + "{}{}{}{}".format( + Style.BRIGHT, + Fore.BLUE, + msg_host, + "*" * (80 - len(msg_host)), + ) + ) + res_sum, ch_sum, f_sum = _print_stat( + host_data, count, res_sum, ch_sum, f_sum + ) + elif isinstance(result, MultiResult): + for res in result: + res_sum, ch_sum, f_sum = _print_stat( + res, count, res_sum, ch_sum, f_sum + ) + elif isinstance(result, Result): + res_sum, ch_sum, f_sum = _print_individual_stat( + result, res_sum, ch_sum, f_sum + ) + + return res_sum, ch_sum, f_sum + + +def print_stat(result: Result, count: Optional[int] = None) -> None: + """ + Prints statistic for `nornir.core.task.Result` object + + Args: + result: From a previous task + count: Number of sorted results. It's acceptable + to use numbers with minus sign(-5, as an example), + then results will be from the end of results list + + Returns: + N/A + + Raises: + N/A + """ + LOCK.acquire() + try: + res_sum, ch_sum, f_sum = _print_stat( + result, + count=count, + res_sum=0, + ch_sum=0, + f_sum=0, + ) + print() + for state, summary, color in zip( + ("OK", "CHANGED", "FAILED"), + (res_sum - f_sum, ch_sum, f_sum), + (Fore.GREEN, Fore.YELLOW, Fore.RED), + ): + print("{}{}{:<8}: {}".format(Style.BRIGHT, color, state, summary)) + finally: + LOCK.release() diff --git a/nornir_utils/plugins/functions/write_result.py b/nornir_utils/plugins/functions/write_result.py new file mode 100644 index 0000000..952759f --- /dev/null +++ b/nornir_utils/plugins/functions/write_result.py @@ -0,0 +1,196 @@ +import os +import logging +import threading +import json +from pathlib import Path +from typing import List, Optional, IO, AnyStr +from nornir_utils.plugins.tasks.files.write_file import _generate_diff +from nornir_utils.plugins.functions.print_result import _slice_result +from nornir.core.task import AggregatedResult, MultiResult, Result + + +LOCK = threading.Lock() + + +def _write_individual_result( + result: Result, + io: IO[AnyStr], + attrs: List[str], + failed: bool, + severity_level: int, + task_group: bool = False, + write_host: bool = False, + no_errors: bool = False, + content: List[str] = [], +) -> List[str]: + + # ignore results with a specific severity_level + if result.severity_level < severity_level: + return content + + # ignore results with errors + if no_errors: + if result.exception: + return content + + subtitle = ( + "" + if result.changed is None + else " ** changed : {} ".format(result.changed) + ) + level_name = logging.getLevelName(result.severity_level) + symbol = "v" if task_group else "-" + host = ( + f"{result.host.name}: " + if (write_host and result.host and result.host.name) + else "" + ) + msg = "{} {}{}{}".format(symbol * 4, host, result.name, subtitle) + content.append("{}{} {}".format(msg, symbol * (80 - len(msg)), level_name)) + for attribute in attrs: + x = getattr(result, attribute, "") + if isinstance(x, BaseException): + # for consistency between py3.6 and py3.7 + content.append(f"{x.__class__.__name__}{x.args}") + elif x and not isinstance(x, str): + try: + content.append( + json.dumps(x, indent=2, ensure_ascii=False) + .encode("utf-8") + .decode() + ) + except TypeError: + content.append(str(x)) + elif x: + content.append(x) + + return content + + +def _write_result( + result: Result, + io: IO[AnyStr], + attrs: List[str] = None, + failed: bool = False, + severity_level: int = logging.INFO, + write_host: bool = False, + count: Optional[int] = None, + no_errors: bool = False, + content: List[str] = [], +) -> List[str]: + + attrs = attrs or ["diff", "result", "stdout"] + if isinstance(attrs, str): + attrs = [attrs] + + if isinstance(result, AggregatedResult): + result = _slice_result(result, count) + for host_data in result.values(): + content = _write_result( + host_data, + io, + attrs, + failed, + severity_level, + write_host, + no_errors=no_errors, + content=content, + ) + elif isinstance(result, MultiResult): + for r in result: + content = _write_result( + r, + io, + attrs, + failed, + severity_level, + write_host, + no_errors=no_errors, + content=content, + ) + elif isinstance(result, Result): + content = _write_individual_result( + result, + io, + attrs, + failed, + severity_level, + write_host=write_host, + no_errors=no_errors, + content=content, + ) + + return content + + +def write_result( + result: Result, + filename: str, + vars: List[str] = None, + failed: bool = False, + severity_level: int = logging.INFO, + write_host: bool = True, + count: Optional[int] = None, + append: bool = False, + no_errors: bool = False, +) -> str: + """ + Writes an object of type `nornir.core.task.Result` to file + + Args: + result: From a previous task + (Result or AggregatedResult or MultiResult) + filename: File you want to write the result + vars: Which attributes you want to write + (see ``class Result`` attributes) + failed: If ``True`` assume the task failed + severity_level: Write only errors with this severity level or higher + write_host: Write hostname to file + count: Limit number of sorted result, written to the file. + It's acceptable to use numbers with minus sign(-5, as an example), + then results will be from the end of results list + append: "a+" if ``True`` or "w+" if ``False`` + no_errors: Don't write results with errors + + Returns: + str: Diff between previous file state and new file state + + Raises: + N/A + """ + + dirname = os.path.dirname(filename) + Path(dirname).mkdir(parents=True, exist_ok=True) + + mode = "a+" if append else "w+" + + LOCK.acquire() + + try: + with open(filename, mode=mode) as f: + content: List[str] = _write_result( + result, + io=f, + attrs=vars, + failed=failed, + severity_level=severity_level, + write_host=write_host, + count=count, + no_errors=no_errors, + content=[], + ) + + lf = ( + "\n\n" if Path(filename).stat().st_size != 0 and append else "" + ) + + lines = [line.strip() for line in content] + line = lf + "\n\n".join(lines) + + diff = _generate_diff(filename, line, append) + + f.write(line) + + return diff + finally: + LOCK.release() diff --git a/nornir_utils/plugins/functions/write_results.py b/nornir_utils/plugins/functions/write_results.py new file mode 100644 index 0000000..6eb1b14 --- /dev/null +++ b/nornir_utils/plugins/functions/write_results.py @@ -0,0 +1,217 @@ +import os +import json +import logging +import threading +from pathlib import Path +from typing import List, Optional, Tuple, Dict +from nornir.core.task import AggregatedResult, MultiResult, Result +from nornir_utils.plugins.functions.print_result import _slice_result +from nornir_utils.plugins.tasks.files.write_file import _generate_diff + + +LOCK = threading.Lock() + + +def _write_individual_result( + result: Result, + dirname: str, + attrs: List[str], + failed: bool, + severity_level: int, + task_group: bool = False, + write_host: bool = False, + no_errors: bool = False, + append: bool = False, + content: Dict[str, List[str]] = {}, +) -> Dict[str, List[str]]: + + individual_result = [] + + # ignore results with a specific severity_level + if result.severity_level < severity_level: + return content + + # ignore results with errors + if no_errors and result.exception: + return content + + filename = str(result.host) + + subtitle = ( + "" + if result.changed is None + else " ** changed : {} ".format(result.changed) + ) + level_name = logging.getLevelName(result.severity_level) + symbol = "v" if task_group else "-" + host = f"{filename}: " if write_host else "" + msg = "{} {}{}{}".format(symbol * 4, host, result.name, subtitle) + individual_result.append( + "{}{} {}".format(msg, symbol * (80 - len(msg)), level_name) + ) + for attribute in attrs: + x = getattr(result, attribute, "") + if isinstance(x, BaseException): + # for consistency between py3.6 and py3.7 + individual_result.append(f"{x.__class__.__name__}{x.args}") + elif x and not isinstance(x, str): + try: + individual_result.append( + json.dumps(x, indent=2, ensure_ascii=False) + .encode("utf-8") + .decode() + ) + except TypeError: + individual_result.append(str(x)) + elif x: + individual_result.append(x) + + lines = [line.strip() for line in individual_result] + content[filename].extend(lines) + + return content + + +def _write_results( + result: Result, + dirname: str, + attrs: List[str] = None, + failed: bool = False, + severity_level: int = logging.INFO, + write_host: bool = False, + count: Optional[int] = None, + no_errors: bool = False, + append: bool = False, + content: Dict[str, List[str]] = {}, +) -> Dict[str, List[str]]: + + attrs = attrs or ["diff", "result", "stdout"] + if isinstance(attrs, str): + attrs = [attrs] + + if isinstance(result, AggregatedResult): + result = _slice_result(result, count) + for host_data in result.values(): + content = _write_results( + host_data, + dirname, + attrs, + failed, + severity_level, + write_host, + no_errors=no_errors, + append=append, + content=content, + ) + elif isinstance(result, MultiResult): + for r in result: + # collect the results to dict, where key = result.host.name + if result.host and result.host.name: + filename = result.host.name + if filename not in content.keys(): + content[filename] = [] + else: + continue + content = _write_results( + r, + dirname, + attrs, + failed, + severity_level, + write_host, + no_errors=no_errors, + append=append, + content=content, + ) + elif isinstance(result, Result): + content = _write_individual_result( + result, + dirname, + attrs, + failed, + severity_level, + write_host=write_host, + no_errors=no_errors, + append=append, + content=content, + ) + + return content + + +def write_results( + result: Result, + dirname: str, + vars: List[str] = None, + failed: bool = False, + severity_level: int = logging.INFO, + write_host: bool = True, + count: Optional[int] = None, + no_errors: bool = False, + append: bool = False, +) -> List[Tuple[str, str]]: + """ + Writes an object of type `nornir.core.task.Result` + to files with hostname names + + Args: + result: From a previous task(Result or AggregatedResult or MultiResult) + dirname: Directory you want to write into + vars: Which attributes you want to write + (see ``class Result`` attributes) + failed: If ``True`` assume the task failed + severity_level: Write only errors with this severity level or higher + write_host: Write hostname to file + count: Limit number of sorted results, written to the files. + It's acceptable to use numbers with minus sign(-5, as an example), + then results will be from the end of results list + no_errors: Don't write results with errors + append: "a+" if ``True`` or "w+" if ``False`` + + Returns: + List[Tuple[str, str]]: List of tuples with hostname + diff + between previous file state and new file state + + Raises: + N/A + """ + Path(dirname).mkdir(parents=True, exist_ok=True) + + mode = "a+" if append else "w+" + + LOCK.acquire() + + try: + content: Dict[str, List[str]] = _write_results( + result, + dirname, + attrs=vars, + failed=failed, + severity_level=severity_level, + write_host=write_host, + count=count, + no_errors=no_errors, + append=append, + content={}, + ) + + diffs = [] + + for name, res in content.items(): + path = os.path.join(dirname, name) + with open(path, mode=mode) as f: + line = "\n\n".join(res) + + lf = ( + "\n\n" if Path(path).stat().st_size != 0 and append else "" + ) + + line = lf + line + + diff = _generate_diff(path, line, append) + + f.write(line) + diffs.append((name, diff)) + return diffs + finally: + LOCK.release()