diff --git a/docs/aetest/debugging.rst b/docs/aetest/debugging.rst index 0224720..93997a5 100644 --- a/docs/aetest/debugging.rst +++ b/docs/aetest/debugging.rst @@ -227,8 +227,9 @@ want to pause the testscript execution somewhere & check the current state and/or configuration of your environment, logs, and testbed devices? The **pause on phrase** feature allows you to pause on **any** log messages -generated by the current script run, without requiring any modifications to the -scripts and/or its libraries. When enabled, it actively filters all log messages +generated by the current script run, including CLI output from devices, +without requiring any modifications to the scripts and/or its libraries. +When enabled, it actively filters all log messages propagated to the ``logging.root`` logger, and pauses when a match is found. Three distinct types of pause actions are supported: @@ -486,3 +487,46 @@ Below are some examples of the pause on phrase feature in action: # -> /path/to/my/example/testscript.py[20] test() # (press Ctrl-D to resume execution) # >>> + +The pause will also dump the connection information, including which devices are currently connected. + +.. code-block:: python + + # -------------------------------------------------------------------------------- + # Pause On Phrase: Connection Information + # + # +-------------------+--------------------------------+ + # | Device Property | Value | + # +-------------------+--------------------------------+ + # | Name | device.name | + # | Alias | device.alias | + # | Active Connection | alias of active connection | + # | Status | Connected|Disconnected | + # | Spawn Command | command for active connection | + # | -------- | -------- | + # | Connection Alias | connection alias e.g. cli | + # | Class | Unicon, Gnmi, Netconf, etc | + # | IP | IPV4|IPV6 address | + # | Protocol | ssh, telnet, etc | + # | -------- | -------- | + # | URL | ://: | + # +-------------------+--------------------------------+ + + +.. note:: + + If it is required to connect to the device directly while the test is paused, the device connection must be disconnected + from before it can be accessed directly. + +.. code-block:: python + + >>> import pyats.easypy as ep + >>> dev = ep.runtime.testbed.devices[''] + >>> dev.disconnect() + + # the device can now be connected to in a separate terminal. Once ready to resume the test, + # break the connection and reattach with + + >>> dev.connect() + + diff --git a/docs/aetest/loop.rst b/docs/aetest/loop.rst index 0a5ded3..ab4698e 100644 --- a/docs/aetest/loop.rst +++ b/docs/aetest/loop.rst @@ -28,8 +28,8 @@ it with different parameters during each loop iteration. The following describes each section and their loop capability and behaviors: ``CommonSetup``/``CommonCleanup`` - Common setup and cleanup sections are unique within each test script. They - are run only once per test script execution, and are not loopable. + Common setup and cleanup sections are unique within each TestScript. They + are run only once per TestScript execution, and are not loopable. ``subsection`` Subsections within ``CommonSetup`` and ``CommonCleanup`` are loopable. @@ -38,12 +38,12 @@ The following describes each section and their loop capability and behaviors: ``Testcase`` Testcases are loopable. Each iteration of a looping ``Testcase`` is reported - individually as new test case instances with a different ``uid``. When a + individually as new ``Testcase`` instances with a different ``uid``. When a ``Testcase`` is looped, and all of its contents (setup, tests, and cleanup) are run fully per each iteration. ``setup``/``cleanup`` - Setup and cleanup sections within each test case is unique, and are run + Setup and cleanup sections within each Testcase is unique, and are run only once per ``Testcase``. They cannot be looped individually, but if their parent ``Testcase`` is looped, then they are run once per ``Testcase`` iteration. @@ -52,9 +52,9 @@ The following describes each section and their loop capability and behaviors: Test sections within ``Testcase`` are loopable individually. Each iteration has its own unique id and is reported as a new test section. When a looping ``test`` section's parent ``Testcase`` is - looped, the resulting loops are multiplicative. E.g.: if a test case is - looped ``2x``and contains a test that is also looped ``2x``, that - test would loop ``2x`` per test case loop iteration. + looped, the resulting loops are multiplicative. E.g.: if a Testcase is + looped ``2x`` and contains a test that is also looped ``2x``, that + test would loop ``2x`` per Testcase loop iteration. .. hint:: @@ -93,27 +93,27 @@ section object is then instantiated once for each iteration. def looped_subsection(self): pass - # Defining a test case that loops + # Defining a Testcase that loops # ---------------------------------- - # This test case also contains a test section that is looped twice + # This Testcase also contains a test section that is looped twice @aetest.loop(uids=['testcase_one', 'testcase_two']) class Testcase(aetest.Testcase): - # Setup section of this test case is run once - # every time the test case is looped. + # Setup section of this Testcase is run once + # every time the Testcase is looped. @aetest.setup def setup(self): pass # Looped test section - # both iterations are run per test case iteration + # both iterations are run per Testcase iteration @aetest.loop(uids=['test_one', 'test_two']) @aetest.test def test(self): pass - # Cleanup section of this test case is run once - # every time the test case is looped. + # Cleanup section of this Testcase is run once + # every time the Testcase is looped. @aetest.cleanup def cleanup(self): pass @@ -216,7 +216,7 @@ looped section is then driven to potentially do something different. from pyats import aetest - # Loop this test case with a loop parameter named "a" + # Loop this Testcase with a loop parameter named "a" # and set it to value 2 for the first iteration, # and 3 for the second iteration @aetest.loop(a=[2, 3]) @@ -229,7 +229,7 @@ looped section is then driven to potentially do something different. # this test prints the exponential of two inputs, a and b print("%s ^ %s = %s" % (a, b, a**b)) - # The output of the test case would look like this: + # The output of the Testcase would look like this: # 2 ^ 8 = 256 # 2 ^ 9 = 512 # 3 ^ 8 = 6561 @@ -449,7 +449,7 @@ would normally expect it to: def test_two(self, b): print('b = %s' % b) - # The output of the test case would be: + # The output of the Testcase would be: # returning [1, 2, 3] # a = 1 # a = 2 @@ -482,7 +482,7 @@ Dynamic Loop Marking -------------------- So far, all loop examples focus on defining the ``@loop`` decorator directly within the -test scripts. E.g., the ``@loop`` decorators are coded as part of the test script. +TestScripts. E.g., the ``@loop`` decorators are coded as part of the TestScript. However, it is also possible to dynamically mark sections for looping during runtime, e.g., creating loops based on information that is only available during a script’s run. To do this, use the ``loop.mark()`` function. @@ -506,7 +506,7 @@ a script’s run. To do this, use the ``loop.mark()`` function. aetest.loop.mark(self.simple_test, uids=['test_one', 'test_two']) # Note: the simple_test section is not directly marked for looping - # instead, during runtime, its testcase's setup section marks it for + # instead, during runtime, its Testcase's setup section marks it for # looping dynamically. @aetest.test @@ -515,7 +515,7 @@ a script’s run. To do this, use the ``loop.mark()`` function. # by using the internal parameter "section" print("current section: %s" % section.uid) - # Output of this test case + # Output of this Testcase # current section: test_one # current section: test_two # @@ -656,9 +656,9 @@ wish to customize loop behavior, it is possible to extend and override it. # This loop generator can be used as the @loop and loop.mark() argument. - # Let's define a looped test case with it. + # Let's define a looped Testcase with it. - # Looping this test case with a custom generator, and a=1, b=5 + # Looping this Testcase with a custom generator, and a=1, b=5 @aetest.loop(generator=DemoGenerator, a=1, b=5) class Testcase(aetest.Testcase): @@ -668,7 +668,7 @@ wish to customize loop behavior, it is possible to extend and override it. def test(self, number): print('current number: %s' % number) - # Output of this test case + # Output of this Testcase # current number: 1 # current number: 2 # current number: 3 diff --git a/docs/apidoc/easypy/pyats.easypy.runinfo.rst b/docs/apidoc/easypy/pyats.easypy.runinfo.rst index e75abb5..d7dda52 100644 --- a/docs/apidoc/easypy/pyats.easypy.runinfo.rst +++ b/docs/apidoc/easypy/pyats.easypy.runinfo.rst @@ -22,14 +22,4 @@ Submodules :show-inheritance: -.. automodule:: pyats.easypy.runinfo.kafka - :members: - :undoc-members: - :show-inheritance: - - -.. automodule:: pyats.easypy.runinfo.s3 - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/apidoc/index.rst b/docs/apidoc/index.rst index 33145ac..8522a8a 100644 --- a/docs/apidoc/index.rst +++ b/docs/apidoc/index.rst @@ -13,7 +13,6 @@ API Documentation robot/index async/index datastructures/index - tcl/index log/index reporter/index results/index diff --git a/docs/apidoc/kleenex/index.rst b/docs/apidoc/kleenex/index.rst index e18e20f..c0e63fe 100644 --- a/docs/apidoc/kleenex/index.rst +++ b/docs/apidoc/kleenex/index.rst @@ -11,38 +11,39 @@ Subpackages .. toctree:: - pyats.kleenex.loader + pyats.clean.loader pyats.kleenex.reporter + pyats.bringup Submodules ---------- -.. automodule:: pyats.kleenex.bases +.. automodule:: pyats.bringup.bases :members: :undoc-members: :show-inheritance: -.. automodule:: pyats.kleenex.bringup_base_cli_parser +.. automodule:: pyats.bringup.base_cli_parser :members: :undoc-members: :show-inheritance: -.. automodule:: pyats.kleenex.bringup_manager +.. automodule:: pyats.bringup.manager :members: :undoc-members: :show-inheritance: -.. automodule:: pyats.kleenex.bringup_manager_cli_parser +.. automodule:: pyats.bringup.manager_cli_parser :members: :undoc-members: :show-inheritance: -.. automodule:: pyats.kleenex.bringup_signals +.. automodule:: pyats.bringup.signals :members: :undoc-members: :show-inheritance: @@ -66,19 +67,19 @@ Submodules :show-inheritance: -.. automodule:: pyats.kleenex.kleenex_traceback +.. automodule:: pyats.clean.traceback :members: :undoc-members: :show-inheritance: -.. automodule:: pyats.kleenex.schema +.. automodule:: pyats.clean.schema :members: :undoc-members: :show-inheritance: -.. automodule:: pyats.kleenex.utils +.. automodule:: pyats.clean.utils :members: :undoc-members: :show-inheritance: diff --git a/docs/apidoc/kleenex/pyats.kleenex.loader.rst b/docs/apidoc/kleenex/pyats.clean.loader.rst similarity index 59% rename from docs/apidoc/kleenex/pyats.kleenex.loader.rst rename to docs/apidoc/kleenex/pyats.clean.loader.rst index d849f47..1a42c06 100644 --- a/docs/apidoc/kleenex/pyats.kleenex.loader.rst +++ b/docs/apidoc/kleenex/pyats.clean.loader.rst @@ -1,7 +1,7 @@ -pyats.kleenex.loader package +pyats.clean.loader package ============================ -.. automodule:: pyats.kleenex.loader +.. automodule:: pyats.clean.loader :members: :undoc-members: :show-inheritance: @@ -10,7 +10,7 @@ Submodules ---------- -.. automodule:: pyats.kleenex.loader.markup +.. automodule:: pyats.clean.loader.markup :members: :undoc-members: :show-inheritance: diff --git a/docs/apidoc/kleenex/pyats.kleenex.reporter.rst b/docs/apidoc/kleenex/pyats.kleenex.reporter.rst index e05f0cf..56a0c52 100644 --- a/docs/apidoc/kleenex/pyats.kleenex.reporter.rst +++ b/docs/apidoc/kleenex/pyats.kleenex.reporter.rst @@ -10,19 +10,7 @@ Submodules ---------- -.. automodule:: pyats.kleenex.reporter.base - :members: - :undoc-members: - :show-inheritance: - - -.. automodule:: pyats.kleenex.reporter.clean - :members: - :undoc-members: - :show-inheritance: - - -.. automodule:: pyats.kleenex.reporter.context +.. automodule:: pyats.kleenex.reporter.reporter :members: :undoc-members: :show-inheritance: diff --git a/docs/apidoc/log/index.rst b/docs/apidoc/log/index.rst index 1d1414e..a9723df 100644 --- a/docs/apidoc/log/index.rst +++ b/docs/apidoc/log/index.rst @@ -12,6 +12,7 @@ Subpackages .. toctree:: pyats.log.commands + pyats.atslog Submodules ---------- diff --git a/docs/apidoc/log/pyats.log.commands.parser.rst b/docs/apidoc/log/pyats.log.commands.parser.rst index 45a28f0..33cb2ea 100644 --- a/docs/apidoc/log/pyats.log.commands.parser.rst +++ b/docs/apidoc/log/pyats.log.commands.parser.rst @@ -10,19 +10,19 @@ Submodules ---------- -.. automodule:: pyats.log.commands.parser.base +.. automodule:: pyats.log.commands.parser.base_parser :members: :undoc-members: :show-inheritance: -.. automodule:: pyats.log.commands.parser.xml +.. automodule:: pyats.log.commands.parser.xml_parser :members: :undoc-members: :show-inheritance: -.. automodule:: pyats.log.commands.parser.yaml +.. automodule:: pyats.log.commands.parser.yaml_parser :members: :undoc-members: :show-inheritance: diff --git a/docs/apidoc/tcl/index.rst b/docs/apidoc/tcl/index.rst deleted file mode 100644 index fb8ff7b..0000000 --- a/docs/apidoc/tcl/index.rst +++ /dev/null @@ -1,59 +0,0 @@ -pyats.tcl package -================= - -.. automodule:: pyats.tcl - :members: - :undoc-members: - :show-inheritance: - -Submodules ----------- - - -.. automodule:: pyats.tcl.array - :members: - :undoc-members: - :show-inheritance: - - -.. automodule:: pyats.tcl.history - :members: - :undoc-members: - :show-inheritance: - - -.. automodule:: pyats.tcl.internal - :members: - :undoc-members: - :show-inheritance: - - -.. automodule:: pyats.tcl.interpreter - :members: - :undoc-members: - :show-inheritance: - - -.. automodule:: pyats.tcl.keyedlist - :members: - :undoc-members: - :show-inheritance: - - -.. automodule:: pyats.tcl.namespace - :members: - :undoc-members: - :show-inheritance: - - -.. automodule:: pyats.tcl.q - :members: - :undoc-members: - :show-inheritance: - - -.. automodule:: pyats.tcl.tclstr - :members: - :undoc-members: - :show-inheritance: - diff --git a/docs/changelog/2020/index.rst b/docs/changelog/2020/index.rst index 0eac7d5..20aa920 100644 --- a/docs/changelog/2020/index.rst +++ b/docs/changelog/2020/index.rst @@ -10,8 +10,8 @@ sep aug jul - jun may apr mar + feb jan \ No newline at end of file diff --git a/docs/changelog/2022/august.rst b/docs/changelog/2022/august.rst new file mode 100644 index 0000000..fc3b4be --- /dev/null +++ b/docs/changelog/2022/august.rst @@ -0,0 +1,76 @@ +August 2022 +========== + +August 26 - Pyats v22.8 +------------------------ + + + +.. csv-table:: New Module Versions + :header: "Modules", "Version" + + ``pyats``, v22.8 + ``pyats.aereport``, v22.8 + ``pyats.aetest``, v22.8 + ``pyats.async``, v22.8 + ``pyats.cisco``, v22.8 + ``pyats.connections``, v22.8 + ``pyats.datastructures``, v22.8 + ``pyats.easypy``, v22.8 + ``pyats.kleenex``, v22.8 + ``pyats.log``, v22.8 + ``pyats.reporter``, v22.8 + ``pyats.results``, v22.8 + ``pyats.robot``, v22.8 + ``pyats.tcl``, v22.8 + ``pyats.topology``, v22.8 + ``pyats.utils``, v22.8 + +Upgrade Instructions +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + # DevNet Community + bash$ pip install --upgrade pyats + + # Cisco Internal Developers + bash$ pip install --upgrade ats + + + + +Changelogs +^^^^^^^^^^ +-------------------------------------------------------------------------------- + Fix +-------------------------------------------------------------------------------- + +* pyats.easypy + * Fixed task-uids filter when using default Task IDs (e.g. Task-2) + +* pyats.manifest + * Add support for boolean overrides with `pyats manifest` CLI command + +* manifest + * combine_cli_args_and_script_arguments + * Handling for any number of uses of the ``--meta`` argument + +* pyats.topology + * Updated testbed.raw_config to contain post-extend, post-markup content. This fixes issues introduced by previous changes when using Genie jinja configure and YAML reference markup. + +* pyats.utils + * Updated schemaengine to support optional advanced datatypes + * Updated yaml loader to support advanced datatypes argument + * Updated yaml loader to store raw/pre/mark/validated/post content + + +-------------------------------------------------------------------------------- + New +-------------------------------------------------------------------------------- + +* ats.cisco + * bussinesstelemetry + * Updated get_paches for collecting package from requirements.txt + + diff --git a/docs/changelog/2022/july.rst b/docs/changelog/2022/july.rst new file mode 100644 index 0000000..8f723cd --- /dev/null +++ b/docs/changelog/2022/july.rst @@ -0,0 +1,64 @@ +July 2022 +========== + +July 26 - Pyats v22.7 +------------------------ + + + +.. csv-table:: New Module Versions + :header: "Modules", "Version" + + ``pyats``, v22.7 + ``pyats.aereport``, v22.7 + ``pyats.aetest``, v22.7 + ``pyats.async``, v22.7 + ``pyats.cisco``, v22.7 + ``pyats.connections``, v22.7 + ``pyats.datastructures``, v22.7 + ``pyats.easypy``, v22.7 + ``pyats.kleenex``, v22.7 + ``pyats.log``, v22.7 + ``pyats.reporter``, v22.7 + ``pyats.results``, v22.7 + ``pyats.robot``, v22.7 + ``pyats.tcl``, v22.7 + ``pyats.topology``, v22.7 + ``pyats.utils``, v22.7 + +Upgrade Instructions +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + # DevNet Community + bash$ pip install --upgrade pyats + + # Cisco Internal Developers + bash$ pip install --upgrade ats + + + + +Changelogs +^^^^^^^^^^ +-------------------------------------------------------------------------------- + Fix +-------------------------------------------------------------------------------- + +* pyats.topology + * Update schema to correctly reflect peripheral structure + +* pyats.easypy + * Modified MailBot: + * Enabled {runtime} formatting for custom subjects on CLI + * Added `email.subject` configuration option + +-------------------------------------------------------------------------------- + New +-------------------------------------------------------------------------------- + +* ats.devat + * Add DevAT package to pyats repo + + diff --git a/docs/changelog/2022/november.rst b/docs/changelog/2022/november.rst new file mode 100644 index 0000000..33d5f71 --- /dev/null +++ b/docs/changelog/2022/november.rst @@ -0,0 +1,52 @@ +November 2022 +========== + +November 28 - Pyats v22.11 +------------------------ + + + +.. csv-table:: New Module Versions + :header: "Modules", "Version" + + ``pyats``, v22.11 + ``pyats.aereport``, v22.11 + ``pyats.aetest``, v22.11 + ``pyats.async``, v22.11 + ``pyats.cisco``, v22.11 + ``pyats.connections``, v22.11 + ``pyats.datastructures``, v22.11 + ``pyats.easypy``, v22.11 + ``pyats.kleenex``, v22.11 + ``pyats.log``, v22.11 + ``pyats.reporter``, v22.11 + ``pyats.results``, v22.11 + ``pyats.robot``, v22.11 + ``pyats.tcl``, v22.11 + ``pyats.topology``, v22.11 + ``pyats.utils``, v22.11 + +Upgrade Instructions +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + # DevNet Community + bash$ pip install --upgrade pyats + + # Cisco Internal Developers + bash$ pip install --upgrade ats + + + + +Changelogs +^^^^^^^^^^ +-------------------------------------------------------------------------------- + Fix +-------------------------------------------------------------------------------- + +* pyats.cisco + * Fix TIMS upload (Cisco internal use only) + + diff --git a/docs/changelog/2022/october.rst b/docs/changelog/2022/october.rst new file mode 100644 index 0000000..cfc27fb --- /dev/null +++ b/docs/changelog/2022/october.rst @@ -0,0 +1,64 @@ +October 2022 +========== + +October 25 - Pyats v22.10 +------------------------ + + + +.. csv-table:: New Module Versions + :header: "Modules", "Version" + + ``pyats``, v22.10 + ``pyats.aereport``, v22.10 + ``pyats.aetest``, v22.10 + ``pyats.async``, v22.10 + ``pyats.cisco``, v22.10 + ``pyats.connections``, v22.10 + ``pyats.datastructures``, v22.10 + ``pyats.easypy``, v22.10 + ``pyats.kleenex``, v22.10 + ``pyats.log``, v22.10 + ``pyats.reporter``, v22.10 + ``pyats.results``, v22.10 + ``pyats.robot``, v22.10 + ``pyats.tcl``, v22.10 + ``pyats.topology``, v22.10 + ``pyats.utils``, v22.10 + +Upgrade Instructions +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + # DevNet Community + bash$ pip install --upgrade pyats + + # Cisco Internal Developers + bash$ pip install --upgrade ats + + + + +Changelogs +^^^^^^^^^^ +-------------------------------------------------------------------------------- + Fix +-------------------------------------------------------------------------------- + +* pyats.utils + * Updated markup processer to support keys() as target + * Support %EXTEND_LIST markup to extend one or more lists as a value + * Modified recursive dict update to support hierarchical use of EXTEND_LIST markup + +* log + * Modified archive.py + * Added await to fix the bug where exposed API calls for results does not return file contents. + +* reporter + * Added Schema + * schema for results.json + * Modified commands.py + * added pyats validate results + + diff --git a/docs/changelog/2022/september.rst b/docs/changelog/2022/september.rst new file mode 100644 index 0000000..f67031f --- /dev/null +++ b/docs/changelog/2022/september.rst @@ -0,0 +1,87 @@ +September 2022 +========== + +September 27 - Pyats v22.9 +------------------------ + + + +.. csv-table:: New Module Versions + :header: "Modules", "Version" + + ``pyats``, v22.9 + ``pyats.aereport``, v22.9 + ``pyats.aetest``, v22.9 + ``pyats.async``, v22.9 + ``pyats.cisco``, v22.9 + ``pyats.connections``, v22.9 + ``pyats.datastructures``, v22.9 + ``pyats.easypy``, v22.9 + ``pyats.kleenex``, v22.9 + ``pyats.log``, v22.9 + ``pyats.reporter``, v22.9 + ``pyats.results``, v22.9 + ``pyats.robot``, v22.9 + ``pyats.tcl``, v22.9 + ``pyats.topology``, v22.9 + ``pyats.utils``, v22.9 + +Upgrade Instructions +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + # DevNet Community + bash$ pip install --upgrade pyats + + # Cisco Internal Developers + bash$ pip install --upgrade ats + + + + +Changelogs +^^^^^^^^^^ + +-------------------------------------------------------------------------------- + Fix +-------------------------------------------------------------------------------- + + +* pyats.topology + * Fixed return exit code for pyats validate testbed + +* pyats installer + * Updated pyATS installer + * Pinned installer dependencies + * Refactor installer builder + +* pyats.cli + * Updated cmd implementation, added encoding and ignoring errors + * Log output of failed commands if available + +* pyats.easypy + * Add support for clean files and logical testbed per task + +* easypy + * Modified Task + * Improved terminate to kill any subprocesses that remain after attempting to terminate + + +-------------------------------------------------------------------------------- + New +-------------------------------------------------------------------------------- + +* pyats + * Pinned pip version to use pip index versions + * Added wrapper for required, legacy and optional packages + +* pyats.cli.commands.version + * Added CheckAvailableVersions + * Created method to get all available versions of a package + * Created method to get the latest version of a list of packages + +* Modified update + * Added latest version to dialog confirming which packages will be updated + * Added --pre argument to fetch minor and dev versions + diff --git a/docs/changelog/2023/april.rst b/docs/changelog/2023/april.rst new file mode 100644 index 0000000..d626248 --- /dev/null +++ b/docs/changelog/2023/april.rst @@ -0,0 +1,73 @@ +April 2023 +========== + +April 25 - Pyats v23.4 +------------------------ + + + +.. csv-table:: New Module Versions + :header: "Modules", "Version" + + ``pyats``, v23.4 + ``pyats.aereport``, v23.4 + ``pyats.aetest``, v23.4 + ``pyats.async``, v23.4 + ``pyats.cisco``, v23.4 + ``pyats.connections``, v23.4 + ``pyats.datastructures``, v23.4 + ``pyats.easypy``, v23.4 + ``pyats.kleenex``, v23.4 + ``pyats.log``, v23.4 + ``pyats.reporter``, v23.4 + ``pyats.results``, v23.4 + ``pyats.robot``, v23.4 + ``pyats.tcl``, v23.4 + ``pyats.topology``, v23.4 + ``pyats.utils``, v23.4 + +Upgrade Instructions +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + # DevNet Community + bash$ pip install --upgrade pyats + + # Cisco Internal Developers + bash$ pip install --upgrade ats + + + + +Changelogs +^^^^^^^^^^ +-------------------------------------------------------------------------------- + Fix +-------------------------------------------------------------------------------- + +* pyats.manifest + * Add support for CLI arguments with * as value + +* pyats.utils + * Fixed default value with CLI markup usage + +* pyats.easypy + * Update the plugin loading in the plugins and update the black_box test. + +* install + * Fix for installer to source venv for pip format json command. + +* update + * Fix to pick up ats packages instead of pyats + + +-------------------------------------------------------------------------------- + New +-------------------------------------------------------------------------------- + +* easypy + * moved AEPluginReporter and AEPluginContext and report_func Wrapper from Plugin Bundle + * move the reporter from plugin bundle to easypy reporter + + diff --git a/docs/changelog/2023/august.rst b/docs/changelog/2023/august.rst new file mode 100644 index 0000000..933aefb --- /dev/null +++ b/docs/changelog/2023/august.rst @@ -0,0 +1,70 @@ +August 2023 +========== + +August 29 - Pyats v23.8 +------------------------ + + + +.. csv-table:: New Module Versions + :header: "Modules", "Version" + + ``pyats``, v23.8 + ``pyats.aereport``, v23.8 + ``pyats.aetest``, v23.8 + ``pyats.async``, v23.8 + ``pyats.cisco``, v23.8 + ``pyats.connections``, v23.8 + ``pyats.datastructures``, v23.8 + ``pyats.easypy``, v23.8 + ``pyats.kleenex``, v23.8 + ``pyats.log``, v23.8 + ``pyats.reporter``, v23.8 + ``pyats.results``, v23.8 + ``pyats.robot``, v23.8 + ``pyats.tcl``, v23.8 + ``pyats.topology``, v23.8 + ``pyats.utils``, v23.8 + +Upgrade Instructions +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + # DevNet Community + bash$ pip install --upgrade pyats + + # Cisco Internal Developers + bash$ pip install --upgrade ats + + + + +Changelogs +^^^^^^^^^^ +-------------------------------------------------------------------------------- + New +-------------------------------------------------------------------------------- + +* pyats.aetest + * Added support for YAML Markup with datafiles, including testbed references + +* pyats.utils + * add new function chainattrget + +* pyats.easypy + * Added section result statistics to job report + + +-------------------------------------------------------------------------------- + Fix +-------------------------------------------------------------------------------- + +* pyats.kleenex + * Update device name mapping logic to support missing entries from orchestrator + * Fix device names used with actual testbed vs logical testbed for use with clean image overrides + +* pyats.utils + * Updated implementation of enforce_max_key_value_length to support hierarchical dictionaries + + diff --git a/docs/changelog/2023/february.rst b/docs/changelog/2023/february.rst new file mode 100644 index 0000000..11ce6bb --- /dev/null +++ b/docs/changelog/2023/february.rst @@ -0,0 +1,60 @@ +February 2023 +========== + +February 28 - Pyats v23.2 +------------------------ + + + +.. csv-table:: New Module Versions + :header: "Modules", "Version" + + ``pyats``, v23.2 + ``pyats.aereport``, v23.2 + ``pyats.aetest``, v23.2 + ``pyats.async``, v23.2 + ``pyats.cisco``, v23.2 + ``pyats.connections``, v23.2 + ``pyats.datastructures``, v23.2 + ``pyats.easypy``, v23.2 + ``pyats.kleenex``, v23.2 + ``pyats.log``, v23.2 + ``pyats.reporter``, v23.2 + ``pyats.results``, v23.2 + ``pyats.robot``, v23.2 + ``pyats.tcl``, v23.2 + ``pyats.topology``, v23.2 + ``pyats.utils``, v23.2 + +Upgrade Instructions +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + # DevNet Community + bash$ pip install --upgrade pyats + + # Cisco Internal Developers + bash$ pip install --upgrade ats + + + + +Changelogs +^^^^^^^^^^ +-------------------------------------------------------------------------------- + New +-------------------------------------------------------------------------------- + +* pyats.utils + * Modified %CLI markup + * Added support for default value, including list syntax support + +* install + * Updated the pyats installer. + * The installer can now install all the required and optional packages. + +* topology + * Updated the schema to support management apis + + diff --git a/docs/changelog/2023/january.rst b/docs/changelog/2023/january.rst new file mode 100644 index 0000000..c8b281a --- /dev/null +++ b/docs/changelog/2023/january.rst @@ -0,0 +1,46 @@ +January 2023 +========== + +January 31 - Pyats v23.1 +------------------------ + + + +.. csv-table:: New Module Versions + :header: "Modules", "Version" + + ``pyats``, v23.1 + ``pyats.aereport``, v23.1 + ``pyats.aetest``, v23.1 + ``pyats.async``, v23.1 + ``pyats.cisco``, v23.1 + ``pyats.connections``, v23.1 + ``pyats.datastructures``, v23.1 + ``pyats.easypy``, v23.1 + ``pyats.kleenex``, v23.1 + ``pyats.log``, v23.1 + ``pyats.reporter``, v23.1 + ``pyats.results``, v23.1 + ``pyats.robot``, v23.1 + ``pyats.tcl``, v23.1 + ``pyats.topology``, v23.1 + ``pyats.utils``, v23.1 + +Upgrade Instructions +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + # DevNet Community + bash$ pip install --upgrade pyats + + # Cisco Internal Developers + bash$ pip install --upgrade ats + + + + +Changelogs +^^^^^^^^^^ + + diff --git a/docs/changelog/2023/july.rst b/docs/changelog/2023/july.rst new file mode 100644 index 0000000..9199c12 --- /dev/null +++ b/docs/changelog/2023/july.rst @@ -0,0 +1,52 @@ +July 2023 +========== + +July 25 - Pyats v23.7 +------------------------ + + + +.. csv-table:: New Module Versions + :header: "Modules", "Version" + + ``pyats``, v23.7 + ``pyats.aereport``, v23.7 + ``pyats.aetest``, v23.7 + ``pyats.async``, v23.7 + ``pyats.cisco``, v23.7 + ``pyats.connections``, v23.7 + ``pyats.datastructures``, v23.7 + ``pyats.easypy``, v23.7 + ``pyats.kleenex``, v23.7 + ``pyats.log``, v23.7 + ``pyats.reporter``, v23.7 + ``pyats.results``, v23.7 + ``pyats.robot``, v23.7 + ``pyats.tcl``, v23.7 + ``pyats.topology``, v23.7 + ``pyats.utils``, v23.7 + +Upgrade Instructions +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + # DevNet Community + bash$ pip install --upgrade pyats + + # Cisco Internal Developers + bash$ pip install --upgrade ats + + + + +Changelogs +^^^^^^^^^^ +-------------------------------------------------------------------------------- + Fix +-------------------------------------------------------------------------------- + +* ats.kleenex + * Allow users to override device `type` and `alias` with values from logical testbed + + diff --git a/docs/changelog/2023/june.rst b/docs/changelog/2023/june.rst new file mode 100644 index 0000000..043a324 --- /dev/null +++ b/docs/changelog/2023/june.rst @@ -0,0 +1,55 @@ +June 2023 +========== + +June 27 - Pyats v23.6 +------------------------ + + + +.. csv-table:: New Module Versions + :header: "Modules", "Version" + + ``pyats``, v23.6 + ``pyats.aereport``, v23.6 + ``pyats.aetest``, v23.6 + ``pyats.async``, v23.6 + ``pyats.cisco``, v23.6 + ``pyats.connections``, v23.6 + ``pyats.datastructures``, v23.6 + ``pyats.easypy``, v23.6 + ``pyats.kleenex``, v23.6 + ``pyats.log``, v23.6 + ``pyats.reporter``, v23.6 + ``pyats.results``, v23.6 + ``pyats.robot``, v23.6 + ``pyats.tcl``, v23.6 + ``pyats.topology``, v23.6 + ``pyats.utils``, v23.6 + +Upgrade Instructions +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + # DevNet Community + bash$ pip install --upgrade pyats + + # Cisco Internal Developers + bash$ pip install --upgrade ats + + + + +Changelogs +^^^^^^^^^^ +-------------------------------------------------------------------------------- + Fix +-------------------------------------------------------------------------------- + +* pyats.easypy + * Fixed issue with multiprocessing causing socket usage collisions + +* pyats.kleenex + * Updated bringup logic to allow users to specify any interface type + + diff --git a/docs/changelog/2023/march.rst b/docs/changelog/2023/march.rst new file mode 100644 index 0000000..09be568 --- /dev/null +++ b/docs/changelog/2023/march.rst @@ -0,0 +1,55 @@ +March 2023 +========== + +March 28 - Pyats v23.3 +------------------------ + + + +.. csv-table:: New Module Versions + :header: "Modules", "Version" + + ``pyats``, v23.3 + ``pyats.aereport``, v23.3 + ``pyats.aetest``, v23.3 + ``pyats.async``, v23.3 + ``pyats.cisco``, v23.3 + ``pyats.connections``, v23.3 + ``pyats.datastructures``, v23.3 + ``pyats.easypy``, v23.3 + ``pyats.kleenex``, v23.3 + ``pyats.log``, v23.3 + ``pyats.reporter``, v23.3 + ``pyats.results``, v23.3 + ``pyats.robot``, v23.3 + ``pyats.tcl``, v23.3 + ``pyats.topology``, v23.3 + ``pyats.utils``, v23.3 + +Upgrade Instructions +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + # DevNet Community + bash$ pip install --upgrade pyats + + # Cisco Internal Developers + bash$ pip install --upgrade ats + + + + +Changelogs +^^^^^^^^^^ +-------------------------------------------------------------------------------- + Fix +-------------------------------------------------------------------------------- + +* pyats.manifest + * Add support for CLI arguments with * as value + +* pyats.utils + * Fixed default value with CLI markup usage + + diff --git a/docs/changelog/2023/may.rst b/docs/changelog/2023/may.rst new file mode 100644 index 0000000..c8fc75b --- /dev/null +++ b/docs/changelog/2023/may.rst @@ -0,0 +1,70 @@ +May 2023 +========== + +May 30 - Pyats v23.5 +------------------------ + + + +.. csv-table:: New Module Versions + :header: "Modules", "Version" + + ``pyats``, v23.5 + ``pyats.aereport``, v23.5 + ``pyats.aetest``, v23.5 + ``pyats.async``, v23.5 + ``pyats.cisco``, v23.5 + ``pyats.connections``, v23.5 + ``pyats.datastructures``, v23.5 + ``pyats.easypy``, v23.5 + ``pyats.kleenex``, v23.5 + ``pyats.log``, v23.5 + ``pyats.reporter``, v23.5 + ``pyats.results``, v23.5 + ``pyats.robot``, v23.5 + ``pyats.tcl``, v23.5 + ``pyats.topology``, v23.5 + ``pyats.utils``, v23.5 + +Upgrade Instructions +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + # DevNet Community + bash$ pip install --upgrade pyats + + # Cisco Internal Developers + bash$ pip install --upgrade ats + + + + +Changelogs +^^^^^^^^^^ +-------------------------------------------------------------------------------- + Fix +-------------------------------------------------------------------------------- + +* pyats.pyats + * Add a cli for manifest to use symlink + +* pyats.easypy + * Add checking for using symlink for the manifest + * Update manifest execution logic to allow jobfiles to be symlinked to another folder + +* aetest + * Modified PausePdb + * Dumps the connection information from the testbed to the console + + +-------------------------------------------------------------------------------- + New +-------------------------------------------------------------------------------- + +* easypy + * Added suite_id to all the jobs reports + * Add suite_name to report data from suite-name CLI argument + * Added label and component reporting options + + diff --git a/docs/changelog/2023/november.rst b/docs/changelog/2023/november.rst new file mode 100644 index 0000000..3b585e4 --- /dev/null +++ b/docs/changelog/2023/november.rst @@ -0,0 +1,95 @@ +November 2023 +========== + +November 27 - Pyats v23.11 +------------------------ + + + +.. csv-table:: New Module Versions + :header: "Modules", "Version" + + ``pyats``, v23.11 + ``pyats.aereport``, v23.11 + ``pyats.aetest``, v23.11 + ``pyats.async``, v23.11 + ``pyats.cisco``, v23.11 + ``pyats.connections``, v23.11 + ``pyats.datastructures``, v23.11 + ``pyats.easypy``, v23.11 + ``pyats.kleenex``, v23.11 + ``pyats.log``, v23.11 + ``pyats.reporter``, v23.11 + ``pyats.results``, v23.11 + ``pyats.robot``, v23.11 + ``pyats.tcl``, v23.11 + ``pyats.topology``, v23.11 + ``pyats.utils``, v23.11 + +Upgrade Instructions +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + # DevNet Community + bash$ pip install --upgrade pyats + + # Cisco Internal Developers + bash$ pip install --upgrade ats + + + + +Changelogs +^^^^^^^^^^ +-------------------------------------------------------------------------------- + New +-------------------------------------------------------------------------------- + +* bringup.bases + * Added authenticate method to BringUpWorkerBase + * Class method to handle authentication before bringup + +* bringup.manager + * Modified __enter__ to authenticate + * Authentication is done (if required) before start_server is called + +* reporter + * Modified Testsuite/Task report + * Testsuite and Task now have an overall result in the final report + + +-------------------------------------------------------------------------------- + Fix +-------------------------------------------------------------------------------- + +* clean + * Modified bases.py + * Set default loglevel to be inherited from pyats + +* kleenex + * Modified kleenex package structure + * Split kleenex into bringup, clean, kleenex + * Bringup contains the scripts to bringup logical devices + * Clean contains the scripts common to bringup and kleenex + * Kleenex contains the scripts to execute clean + * Fixed issue with kleenex loader where the `--clean-image-json` argument wouldn't allow for device aliases to be passed + * Added unittests to verify changes + +* easypy + * Modified kleenex plugin + * Updated references to kleenex package structure + +* pyats.topology + * Updated schema to support services for testbed servers. + +* manifest + * Fixed issue with `parse_cli_args` where the `meta` argument would get nested in lists if it was specified more than two times + +* pyats.connections.bases + * Add CLI arguments to service wrapper + * Updated docs + * Detached service wrapper from easypy runtime + * Added steps to service wrapper methods to allow for reporting + + diff --git a/docs/changelog/2023/october.rst b/docs/changelog/2023/october.rst new file mode 100644 index 0000000..e4f64f3 --- /dev/null +++ b/docs/changelog/2023/october.rst @@ -0,0 +1,65 @@ +October 2023 +========== + +October 31 - Pyats v23.10 +------------------------ + + + +.. csv-table:: New Module Versions + :header: "Modules", "Version" + + ``pyats``, v23.10 + ``pyats.aereport``, v23.10 + ``pyats.aetest``, v23.10 + ``pyats.async``, v23.10 + ``pyats.cisco``, v23.10 + ``pyats.connections``, v23.10 + ``pyats.datastructures``, v23.10 + ``pyats.easypy``, v23.10 + ``pyats.kleenex``, v23.10 + ``pyats.log``, v23.10 + ``pyats.reporter``, v23.10 + ``pyats.results``, v23.10 + ``pyats.robot``, v23.10 + ``pyats.tcl``, v23.10 + ``pyats.topology``, v23.10 + ``pyats.utils``, v23.10 + +Upgrade Instructions +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + # DevNet Community + bash$ pip install --upgrade pyats + + # Cisco Internal Developers + bash$ pip install --upgrade ats + + + + +Changelogs +^^^^^^^^^^ +-------------------------------------------------------------------------------- + Fix +-------------------------------------------------------------------------------- + +* pyats.kleenex + * Modified markup processor to use chainattrget utility function to allow object attribute and key lookup + +* easypy + * Modified update_job + * Modified update_job to format elapsedtime + + +-------------------------------------------------------------------------------- + New +-------------------------------------------------------------------------------- + +* topology + * Updated schema for fallback credentials + * Add fallback credentials under connection + + diff --git a/docs/changelog/2023/september.rst b/docs/changelog/2023/september.rst new file mode 100644 index 0000000..d14fb2b --- /dev/null +++ b/docs/changelog/2023/september.rst @@ -0,0 +1,87 @@ +September 2023 +========== + +September 26 - Pyats v23.9 +------------------------ + + + +.. csv-table:: New Module Versions + :header: "Modules", "Version" + + ``pyats``, v23.9 + ``pyats.aereport``, v23.9 + ``pyats.aetest``, v23.9 + ``pyats.async``, v23.9 + ``pyats.cisco``, v23.9 + ``pyats.connections``, v23.9 + ``pyats.datastructures``, v23.9 + ``pyats.easypy``, v23.9 + ``pyats.kleenex``, v23.9 + ``pyats.log``, v23.9 + ``pyats.reporter``, v23.9 + ``pyats.results``, v23.9 + ``pyats.robot``, v23.9 + ``pyats.tcl``, v23.9 + ``pyats.topology``, v23.9 + ``pyats.utils``, v23.9 + +Upgrade Instructions +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + # DevNet Community + bash$ pip install --upgrade pyats + + # Cisco Internal Developers + bash$ pip install --upgrade ats + + + + +Changelogs +^^^^^^^^^^ +-------------------------------------------------------------------------------- + New +-------------------------------------------------------------------------------- + +* pyats + * Added BaseServiceWrapper class + +* pyats.aetest + * Added support for YAML Markup with datafiles, including testbed references + +* pyats.utils + * add new function chainattrget + * Added duplicate key detection in yaml loader + +* pyats.easypy + * Added section result statistics to job report + + +-------------------------------------------------------------------------------- + Fix +-------------------------------------------------------------------------------- + +* pyats.kleenex + * Update device name mapping logic to support missing entries from orchestrator + * Fix device names used with actual testbed vs logical testbed for use with clean image overrides + +* pyats.topology + * Updated management schema type for protocols. + +* pyats.utils + * Updated implementation of enforce_max_key_value_length to support hierarchical dictionaries + +* kleenex + * Modified KleenexMarkupProcessor + * Delayed processing of testbed markups to support logical testbeds + * Modified kleenex_main + * Reloaded clean file to process testbed markups after topology bringup + +* easypy + * Modified Kleenex Plugin + * Reloaded clean file to process testbed markups after topology bringup + + diff --git a/docs/changelog/2024/September.rst b/docs/changelog/2024/September.rst new file mode 100644 index 0000000..b7d2101 --- /dev/null +++ b/docs/changelog/2024/September.rst @@ -0,0 +1,50 @@ +September 2024 +========== + +September 24 - Pyats v24.9 +------------------------ + + + +.. csv-table:: New Module Versions + :header: "Modules", "Version" + + ``pyats``, v24.9 + ``pyats.aereport``, v24.9 + ``pyats.aetest``, v24.9 + ``pyats.async``, v24.9 + ``pyats.cisco``, v24.9 + ``pyats.connections``, v24.9 + ``pyats.datastructures``, v24.9 + ``pyats.easypy``, v24.9 + ``pyats.kleenex``, v24.9 + ``pyats.log``, v24.9 + ``pyats.reporter``, v24.9 + ``pyats.results``, v24.9 + ``pyats.robot``, v24.9 + ``pyats.tcl``, v24.9 + ``pyats.topology``, v24.9 + ``pyats.utils``, v24.9 + + + + +Changelogs +^^^^^^^^^^ +-------------------------------------------------------------------------------- + New +-------------------------------------------------------------------------------- + +* pyats.connections.wrapper + * Added add_service_wrapper_usage_data function to push service wrapper data to business telemetry. + + +-------------------------------------------------------------------------------- + Fix +-------------------------------------------------------------------------------- + +* topology + * schema + * Added device id to schema + + diff --git a/docs/changelog/2024/april.rst b/docs/changelog/2024/april.rst new file mode 100644 index 0000000..f877e62 --- /dev/null +++ b/docs/changelog/2024/april.rst @@ -0,0 +1,102 @@ +April 2024 +========== + +April 30 - Pyats v24.4 +---------------------- + + + +.. csv-table:: New Module Versions + :header: "Modules", "Version" + + ``pyats``, v24.4 + ``pyats.aereport``, v24.4 + ``pyats.aetest``, v24.4 + ``pyats.async``, v24.4 + ``pyats.cisco``, v24.4 + ``pyats.connections``, v24.4 + ``pyats.datastructures``, v24.4 + ``pyats.easypy``, v24.4 + ``pyats.kleenex``, v24.4 + ``pyats.log``, v24.4 + ``pyats.reporter``, v24.4 + ``pyats.results``, v24.4 + ``pyats.robot``, v24.4 + ``pyats.tcl``, v24.4 + ``pyats.topology``, v24.4 + ``pyats.utils``, v24.4 + +Upgrade Instructions +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + # DevNet Community + bash$ pip install --upgrade pyats + + # Cisco Internal Developers + bash$ pip install --upgrade ats + + + + +Changelogs +^^^^^^^^^^ +-------------------------------------------------------------------------------- + New +-------------------------------------------------------------------------------- + +* pyats.easypy + * Added Tips Plugin + * A new plugin that provides a way to display tips and tricks to users + +* pyats.topology + * Updated Device class `repr`, added alias value + + +-------------------------------------------------------------------------------- + Fix +-------------------------------------------------------------------------------- + +* easypy + * Fix device recovery data type for tftp address + * Modified Plugin Reporting + * Plugins now report errors as results even when the plugin is not specified to report anything. This prevents the overall result showing Passed when a plugin had an error. + +* iosxe + * Added RerunPlugin + * Remove commonSetup, commonCleanup, testcases if it is none. + +* easypy/plugins + * kleenex + * updated logic to add device recovery section even if there are no clean image attributes. + +* pyats.connections + * Modified connection manager + * Updated logic to support service wrapper with connection pools + * Pass Steps object to service wrapper if none found + +* pyats.aetest + * Modified Steps class to support index offset + +* pyats.async + * Support Steps with pcall + * Modified child process logic to update steps offset for child processes + * Add logic to propagate step failures in subprocess + +* bringup + * Manager + * Fixed bug preventing manager from halting exit with pyats clean command + +* kleenex + * loader + * Update to load and check the logical testbed in _preprocess_add_cli_images in order to get correct image_set for iol devices. + +* pyats.cisco + * Fix telemetry upload + +* utils/fileutils + * http + * Added logic for http stat in fileutils. + + diff --git a/docs/changelog/2024/february.rst b/docs/changelog/2024/february.rst new file mode 100644 index 0000000..e0e610f --- /dev/null +++ b/docs/changelog/2024/february.rst @@ -0,0 +1,101 @@ +February 2024 +========== + +February 27 - Pyats v24.2 +------------------------ + + + +.. csv-table:: New Module Versions + :header: "Modules", "Version" + + ``pyats``, v24.2 + ``pyats.aereport``, v24.2 + ``pyats.aetest``, v24.2 + ``pyats.async``, v24.2 + ``pyats.cisco``, v24.2 + ``pyats.connections``, v24.2 + ``pyats.datastructures``, v24.2 + ``pyats.easypy``, v24.2 + ``pyats.kleenex``, v24.2 + ``pyats.log``, v24.2 + ``pyats.reporter``, v24.2 + ``pyats.results``, v24.2 + ``pyats.robot``, v24.2 + ``pyats.tcl``, v24.2 + ``pyats.topology``, v24.2 + ``pyats.utils``, v24.2 + +Upgrade Instructions +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + # DevNet Community + bash$ pip install --upgrade pyats + + # Cisco Internal Developers + bash$ pip install --upgrade ats + + + + +Changelogs +^^^^^^^^^^ +-------------------------------------------------------------------------------- + Add +-------------------------------------------------------------------------------- + +* docker + * Added aarch64 python 3.12 builder + + +-------------------------------------------------------------------------------- + New +-------------------------------------------------------------------------------- + +* makefile + * Added aiohttp package + +* easypy.plugins + * kleenex.py + * Added logic to update device recovery information to clean data. + * kleenex.py + * Added dyntopo entrypoints to take cli args from the workers. + + +-------------------------------------------------------------------------------- + Modify +-------------------------------------------------------------------------------- + +* aetest-pkg + * Removed unused and deprecated imports + * Renamed the file to fix UT issue + +* easypy-pkg + * assertEquals is not support for 3.12 hence changed to assertEqual + +* utils-pkg + * updated import utils with exec_module instead of load_module + + +-------------------------------------------------------------------------------- + Fix +-------------------------------------------------------------------------------- + +* installer + * Modified installer script to remove dependency on pypi.org (Cisco internal use only) + +* pyats.connections + * utils.py + * Fixed bug with set_parameters and added unittest + +* pyats.connections.bases + * Move wrapper to before connection so that `connect` can be wrapped + +* easypy.plugins + * Modified XunitPlugin + * Updated post_job method and separated xunit xml generation code + * Added conditional xunit_include_logs parameter to generate xunit.xml + + diff --git a/docs/changelog/2024/january.rst b/docs/changelog/2024/january.rst new file mode 100644 index 0000000..e962d0c --- /dev/null +++ b/docs/changelog/2024/january.rst @@ -0,0 +1,108 @@ +January 2024 +========== + +30 - Pyats v24.1 +------------------------ + + + +.. csv-table:: New Module Versions + :header: "Modules", "Version" + + ``pyats``, v24.1 + ``pyats.aereport``, v24.1 + ``pyats.aetest``, v24.1 + ``pyats.async``, v24.1 + ``pyats.cisco``, v24.1 + ``pyats.connections``, v24.1 + ``pyats.datastructures``, v24.1 + ``pyats.easypy``, v24.1 + ``pyats.kleenex``, v24.1 + ``pyats.log``, v24.1 + ``pyats.reporter``, v24.1 + ``pyats.results``, v24.1 + ``pyats.robot``, v24.1 + ``pyats.tcl``, v24.1 + ``pyats.topology``, v24.1 + ``pyats.utils``, v24.1 + +Upgrade Instructions +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + # DevNet Community + bash$ pip install --upgrade pyats + + # Cisco Internal Developers + bash$ pip install --upgrade ats + + + + +Changelogs +^^^^^^^^^^ +-------------------------------------------------------------------------------- + Fix +-------------------------------------------------------------------------------- + +* kleenex + * Fixed issue with kleenex loader handling device alias + +* pyats.configuration + * Removed pyATS Configuration object from sys.modules, refactored usage + * Change "from pyats import configuration" to "from pyats.configuration import configuration" + +* log-pkg + * commands + * remove aiohttp-swagger and its references to resolve markupsafe errors + +* pyats.utils + * Updated YAML markup processor to support markup in dictionary keys + +* easypy + * Removed + * Removed duplicate Task Result Details and Task Result Summary + +* pyats.topology + * Updated management schema type for address and gateway. + +* pyats.kleenex + * Modified p_reference_markup + * Parse credentials on testbed.raw_config + + +-------------------------------------------------------------------------------- + New +-------------------------------------------------------------------------------- + +* easypy.plugins + * kleenex.py + * Added preprocessor logic to update default clean image + +* cisco.commands + * Added pyats testbed teardown + * Added command to teardown topology using dyntopo orchestrators + * Added pyats testbed bringup + * Added command to bringup topology using dyntopo orchestrators + +* easypy + * AEReporter + * add skipped to AEPluginReporter + * Kleenex + * Add skip-teardown-on-failure argument to skip teardown when success rate is below 100% + +* pyats.utils + * Added load_dict_from_list + * Added support for meta argument if passed as a list + * Support keyword argument (kwarg) syntax with CALLABLE YAML markup + +* bringup.bases + * Added skip_teardown argument + * Added argument to skip topology teardown after clean/bringup execution. + +* easypy.plugins.kleenex + * Added skip_teardown argument + * Added argument to skip topology teardown after test case execution. + + diff --git a/docs/changelog/2024/july.rst b/docs/changelog/2024/july.rst new file mode 100644 index 0000000..1b207e7 --- /dev/null +++ b/docs/changelog/2024/july.rst @@ -0,0 +1,69 @@ +July 2024 +========== + +July 30 - Pyats v24.7 +------------------------ + + + +.. csv-table:: New Module Versions + :header: "Modules", "Version" + + ``pyats``, v24.7 + ``pyats.aereport``, v24.7 + ``pyats.aetest``, v24.7 + ``pyats.async``, v24.7 + ``pyats.cisco``, v24.7 + ``pyats.connections``, v24.7 + ``pyats.datastructures``, v24.7 + ``pyats.easypy``, v24.7 + ``pyats.kleenex``, v24.7 + ``pyats.log``, v24.7 + ``pyats.reporter``, v24.7 + ``pyats.results``, v24.7 + ``pyats.robot``, v24.7 + ``pyats.tcl``, v24.7 + ``pyats.topology``, v24.7 + ``pyats.utils``, v24.7 + +Upgrade Instructions +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + # DevNet Community + bash$ pip install --upgrade pyats + + # Cisco Internal Developers + bash$ pip install --upgrade ats + + + + +Changelogs +^^^^^^^^^^ +-------------------------------------------------------------------------------- + Fix +-------------------------------------------------------------------------------- + +* pyats.utils + * Modified argv parser helper function + * Ignore arguments after `--` + * Allow `-` to be passed as a value + +* pyats.cli + * Modified version update + * Ignore packages that have no matching version + + +-------------------------------------------------------------------------------- + New +-------------------------------------------------------------------------------- + +* pyats.reporter + * update the log offset for each sub process + +* pyats + * remove init file for declaring namespaces for all the packages to avoid deprecation messages. + + diff --git a/docs/changelog/2024/june.rst b/docs/changelog/2024/june.rst new file mode 100644 index 0000000..277caf3 --- /dev/null +++ b/docs/changelog/2024/june.rst @@ -0,0 +1,63 @@ +June 2024 +========== + + - Pyats v24.6 +------------------------ + + + +.. csv-table:: New Module Versions + :header: "Modules", "Version" + + ``pyats``, v24.6 + ``pyats.aereport``, v24.6 + ``pyats.aetest``, v24.6 + ``pyats.async``, v24.6 + ``pyats.cisco``, v24.6 + ``pyats.connections``, v24.6 + ``pyats.datastructures``, v24.6 + ``pyats.easypy``, v24.6 + ``pyats.kleenex``, v24.6 + ``pyats.log``, v24.6 + ``pyats.reporter``, v24.6 + ``pyats.results``, v24.6 + ``pyats.robot``, v24.6 + ``pyats.tcl``, v24.6 + ``pyats.topology``, v24.6 + ``pyats.utils``, v24.6 + +Upgrade Instructions +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + # DevNet Community + bash$ pip install --upgrade pyats + + # Cisco Internal Developers + bash$ pip install --upgrade ats + + + + +Changelogs +^^^^^^^^^^ +-------------------------------------------------------------------------------- + Fix +-------------------------------------------------------------------------------- + +* easy/plugins + * kleenex + * Fixed clean default image issue. + * kleenex + * Fixed clean default image where multiple images being passed to each device, instead + +* kleenex + * clean/loader + * Fixed a bug with clean templates, where it was not updating the clean image properly. + +* topology + * Modified schema + * Added submodel key in device schema + + diff --git a/docs/changelog/2024/march.rst b/docs/changelog/2024/march.rst new file mode 100644 index 0000000..bef8277 --- /dev/null +++ b/docs/changelog/2024/march.rst @@ -0,0 +1,80 @@ +March 2024 +========== + + - Pyats v24.3 +------------------------ + + + +.. csv-table:: New Module Versions + :header: "Modules", "Version" + + ``pyats``, v24.3 + ``pyats.aereport``, v24.3 + ``pyats.aetest``, v24.3 + ``pyats.async``, v24.3 + ``pyats.cisco``, v24.3 + ``pyats.connections``, v24.3 + ``pyats.datastructures``, v24.3 + ``pyats.easypy``, v24.3 + ``pyats.kleenex``, v24.3 + ``pyats.log``, v24.3 + ``pyats.reporter``, v24.3 + ``pyats.results``, v24.3 + ``pyats.robot``, v24.3 + ``pyats.tcl``, v24.3 + ``pyats.topology``, v24.3 + ``pyats.utils``, v24.3 + +Upgrade Instructions +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + # DevNet Community + bash$ pip install --upgrade pyats + + # Cisco Internal Developers + bash$ pip install --upgrade ats + + + + +Changelogs +^^^^^^^^^^ +-------------------------------------------------------------------------------- + New +-------------------------------------------------------------------------------- + +* easypy.plugins + * rerun + * Added ability to download archive/rerun file from a URL + +* pyats.aetest + * Modified PauseOnPhrase, added collect and custom options + +* pyats.cli + * Migrate abstract + * Added functionality to the `pyats migrate abstract` command to modify the files in-place with the suggested changes + +* easypy + * plugins(kleenex) + * add --clean-template-action cli argument to kleenex plugin. + +* kleenex + * loader + * add logic for loading a template for cleaning the device + + +-------------------------------------------------------------------------------- + Fix +-------------------------------------------------------------------------------- + +* pyats.connection + * Service Wrapper + * Fixed an issue that caused a circular import when using the service wrapper with external connection packages + * Changed `BaseServiceWrapper` to `ServiceWrapper` + * Changed `ServiceWrapper` import from `from pyats.connections.bases import BaseServiceWrapper` to `from pyats.connections import ServiceWrapper` + * This feature replaces the previous concept of Service Hooks + + diff --git a/docs/changelog/2024/may.rst b/docs/changelog/2024/may.rst new file mode 100644 index 0000000..addb779 --- /dev/null +++ b/docs/changelog/2024/may.rst @@ -0,0 +1,77 @@ +May 2024 +========== + +May 28 - Pyats v24.5 +------------------------ + + + +.. csv-table:: New Module Versions + :header: "Modules", "Version" + + ``pyats``, v24.5 + ``pyats.aereport``, v24.5 + ``pyats.aetest``, v24.5 + ``pyats.async``, v24.5 + ``pyats.cisco``, v24.5 + ``pyats.connections``, v24.5 + ``pyats.datastructures``, v24.5 + ``pyats.easypy``, v24.5 + ``pyats.kleenex``, v24.5 + ``pyats.log``, v24.5 + ``pyats.reporter``, v24.5 + ``pyats.results``, v24.5 + ``pyats.robot``, v24.5 + ``pyats.tcl``, v24.5 + ``pyats.topology``, v24.5 + ``pyats.utils``, v24.5 + +Upgrade Instructions +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + # DevNet Community + bash$ pip install --upgrade pyats + + # Cisco Internal Developers + bash$ pip install --upgrade ats + + + + +Changelogs +^^^^^^^^^^ +-------------------------------------------------------------------------------- + Fix +-------------------------------------------------------------------------------- + +* pyats.cisco + * Update package discovery error handling + * Update ABS URL, add environment variable lookup + + +-------------------------------------------------------------------------------- + New +-------------------------------------------------------------------------------- + +* kleenex/worker + * Updated logic to make device alias name as default in reporter. + +* pyats/topology + * schema + * Update topology schema for rommon information. + +* clean + * schema + * Updated clean schema with resources section with memory and cpu. + +* cisco/commands/testbed + * bringup + * Updated logic to pull the dyntopo worker arguments dynamically. + +* cisco/commands + * testbed/export + * Added export subcommand to export the testbed data using laasv2 + + diff --git a/docs/changelog/2024/october.rst b/docs/changelog/2024/october.rst new file mode 100644 index 0000000..5eb7b1f --- /dev/null +++ b/docs/changelog/2024/october.rst @@ -0,0 +1,41 @@ +October 2024 +========== + +October 29 - Pyats v24.10 +------------------------ + + + +.. csv-table:: New Module Versions + :header: "Modules", "Version" + + ``pyats``, v24.10 + ``pyats.aereport``, v24.10 + ``pyats.aetest``, v24.10 + ``pyats.async``, v24.10 + ``pyats.cisco``, v24.10 + ``pyats.connections``, v24.10 + ``pyats.datastructures``, v24.10 + ``pyats.easypy``, v24.10 + ``pyats.kleenex``, v24.10 + ``pyats.log``, v24.10 + ``pyats.reporter``, v24.10 + ``pyats.results``, v24.10 + ``pyats.robot``, v24.10 + ``pyats.tcl``, v24.10 + ``pyats.topology``, v24.10 + ``pyats.utils``, v24.10 + + + + +Changelogs +^^^^^^^^^^ +-------------------------------------------------------------------------------- + Fix +-------------------------------------------------------------------------------- + +* fixed the schema for management routes + * Update to add static route ipv4 + + diff --git a/docs/changelog/index.rst b/docs/changelog/index.rst index f2f7b07..457a653 100644 --- a/docs/changelog/index.rst +++ b/docs/changelog/index.rst @@ -8,6 +8,31 @@ Changelog .. toctree:: :maxdepth: 2 + 2024/october + 2024/September + 2024/july + 2024/june + 2024/may + 2024/april + 2024/march + 2024/february + 2024/january + 2023/november + 2023/october + 2023/september + 2023/august + 2023/july + 2023/june + 2023/may + 2023/april + 2023/march + 2023/february + 2023/january + 2022/november + 2022/october + 2022/september + 2022/august + 2022/july 2022/june 2022/may 2022/april diff --git a/docs/cli/index.rst b/docs/cli/index.rst index 5ed5993..f4ec086 100644 --- a/docs/cli/index.rst +++ b/docs/cli/index.rst @@ -15,6 +15,7 @@ and usage. pyats_create pyats_develop pyats_logs + pyats_migrate pyats_run pyats_secret pyats_shell diff --git a/docs/cli/pyats.rst b/docs/cli/pyats.rst index 8cb59fc..2721dbe 100644 --- a/docs/cli/pyats.rst +++ b/docs/cli/pyats.rst @@ -14,8 +14,18 @@ Synopsis pyats [options] Commands: - validate utlities that helps to validate input files - version display currently installed pyATS version + clean runs the provided clean file + create create scripts and libraries from template + diff Command to diff two snapshots saved to file or directory + learn Command to learn device features and save to file + logs command enabling log archive viewing in local browser + migrate utilities for migrating to future versions of pyATS + parse Command to parse show commands + run runs the provided script and output corresponding results. + secret utilities for working with secret strings. + shell enter Python shell, loading a pyATS testbed file and/or pickled data + validate utilities that help to validate input files + version commands related to version display and manipulation General Options: -h, --help Show help diff --git a/docs/cli/pyats_migrate.rst b/docs/cli/pyats_migrate.rst new file mode 100644 index 0000000..973de7c --- /dev/null +++ b/docs/cli/pyats_migrate.rst @@ -0,0 +1,44 @@ +pyats migrate +============= + +Command to identify and inform a user of required upcoming changes to their +environment. + +.. code-block:: text + + Usage: + pyats migrate [options] + + Subcommands: + abstract Discover what changes must be made to existing test environments to conform + to the new token discovery. + + +pyats migrate abstract +--------------------- + +The mechanism for `Genie Abstract`_ and the organization of `Unicon Supported Platforms`_ +are being updated for better consistency and utility. This subcommand will +examine your environment and inform you of any potential changes that may be +required. The usage of ``os``, ``model``, ``platform`` will be strictly defined within +Unicon in the `PID tokens`_ file and may require updates to testbeds and scripts to correctly reflect +these definitions. + +.. _Genie Abstract: https://pubhub.devnetcloud.com/media/genie-docs/docs/abstract/index.html +.. _Unicon Supported Platforms: https://pubhub.devnetcloud.com/media/unicon/docs/user_guide/supported_platforms.html +.. _PID tokens: https://github.com/CiscoTestAutomation/unicon.plugins/blob/master/src/unicon/plugins/pid_tokens.csv + +.. code-block:: text + + Usage: + pyats migrate abstract [options] + + Description: + Discover what changes must be made to existing test environments to conform to the new token discovery. + + Abstract Options: + path Path to start searching for files + --init Only process __init__.py files + --python Only process Python files + --yaml Only process YAML files + --threads THREADS Max number of threads to run while processing files (default 100) diff --git a/docs/cli/pyats_validate.rst b/docs/cli/pyats_validate.rst index 24a89ae..6518bc1 100644 --- a/docs/cli/pyats_validate.rst +++ b/docs/cli/pyats_validate.rst @@ -11,6 +11,7 @@ related input files, formats, and content. Subcommands: datafile validate your YAML-based datafile syntax + jinja2_config validate genie config file jinja2 rendering testbed validate your testbed file yaml syntax General Options: @@ -225,4 +226,71 @@ Example .. tip:: - use ``-q`` to quiet pretty information such as "----" sections and headers. \ No newline at end of file + use ``-q`` to quiet pretty information such as "----" sections and headers. + + + + +pyats validate jinja2_config +---------------------------- + +This subcommand validates the content of your Genie configuration datafile. It +gives developers an opportunity to check if the file is written following +valid YAML syntax and what the Jinja2 rendered output configuration looks like. + +.. code-block:: text + + Usage: + pyats validate jinja2_config [file] [options] + + Description: + Validates the provided genie config file for jinja2 rendering. + + Jinja2_config Options: + [file] Genie config datafile to validate + --testbed-file TESTBED + Testbed file (required) + --devices DEVICES [DEVICES ...] + Devices to render configs for (optional) + --sequence SEQUENCE [SEQUENCE ...] + Sequence(s) to render (optional) + + General Options: + -h, --help Show help + -v, --verbose Give more output, additive up to 3 times. + -q, --quiet Give less output, additive up to 3 times, corresponding to WARNING, ERROR, + and CRITICAL logging levels + +Options +^^^^^^^ + +``[file]`` + The Genie configuration datafile. Can be a file path or a URL to a YAML file + +``--devices`` + Device names to render the configuration for. Only configurations for these devices will be + used to render configurations. + +``--sequence`` + Sequence(s) to render the configuration for. Only the sequences specified will be rendered. + + +Example +^^^^^^^ + + +.. code-block:: text + + $ pyats validate jinja2_config data/config_datafile.yaml --testbed-file data/testbed.yaml --sequence 1 + + Device R1 sequence 1: + interface Loopback0 + no shutdown + ip address 1.1.1.1 255.255.255.255 + + + Device R2 sequence 1: + interface Loopback0 + no shutdown + ip address 2.2.2.2 255.255.255.255 + diff --git a/docs/configuration/index.rst b/docs/configuration/index.rst index 2d03605..ac46259 100644 --- a/docs/configuration/index.rst +++ b/docs/configuration/index.rst @@ -126,6 +126,8 @@ The following fields are currently open for user to customize. format = # Collect git info, default is True. git_info = + # section reporting, default is "SubSection SetupSection CleanupSection TestSection" + sections = SubSection SetupSection CleanupSection TestSection # configuration related to timestamps [timestamp] diff --git a/docs/connections/hook.rst b/docs/connections/hook.rst deleted file mode 100644 index a151072..0000000 --- a/docs/connections/hook.rst +++ /dev/null @@ -1,173 +0,0 @@ -Connection Hook -=============== - -Whereas a connection class provides the fundamentals of communicating to target -devices using object methods (**services**), the goal of a connection hook is -to *tap* onto particular services and *inject* code to run before and after the -actual service call, **without modifying** the original behavior. - -Here are some typical use cases of connection hooks: - - - tracking the sequence/occurance of CLI command calls throughout a script - - - debug-logging the input arguments to, and output values from particular - services. - - - building a LRU cache based on script inputs and device states. - - - etc. - - -Usage ------ - -A connection hook wraps the original connection service method, and replaces it -during runtime (dynamically). The original functionality of the service remains -intact, but the hook enables uses to add code before/after the service method. - -- all connection hooks should inherit the base ``connections.hooks.ServiceHook`` - class - -- to add code *before a service*, define the ``enter()`` method under your - class. - - - all arguments to the service is passed to ``enter()`` method in the same way - as the original call. - -- to execute code *after a service*, define the ``after()`` method under your - class - - - the return of the service is passed to the ``after()`` method - -- to enable custom error/exception tracking, define a ``error_handle()`` method - under you class. - - - the current exception is passed into the error handler as ``e``. - -- to disable the current hook, call the ``restore()`` method of the hook. - -.. note:: - - error handlers can suppress an exception, and/or track/register it - internally. By default the built-in error handler will simply raise the - current exception. Developer can modify that to suppress the current - exception being handled, and return a fixed/altered result. - - -.. code-block:: python - - # Example - # ------- - # - # a simple tracking implementation - - import pdb - import collections - - from pyats.connections.hooks import ServiceHook - - class Tracker(ServiceHook): - '''A hook implementation intended to count the number of CLI calls, and - track their result returns''' - - def __init__(self, *args, **kwargs): - - # always call the parent - super().__init__(*args, **kwargs) - - # create a local counter - self.counter = collections.Counter() - - # create a command return storage dictionary - self.returns = {} - - def enter(self, cmd, *args, **kwargs): - '''enter - - Track the command occurance (calls) by assuming execute() command's - first argument is the CLI command to run, and ignoring the rest of - the arguments - ''' - - # increment the counter - # (using this command as key) - self.counter[cmd] += 1 - - # store the current command for use in exit() - self.cmd = cmd - - def exit(self, retval): - '''exit - - store the return from the command call in another dictionary - ''' - - # the current command from enter() - cmd = self.cmd - - # current command occurance - index = self.counter[cmd] - - # because a command can be called multiple times, store each - # possible command using a dictionary with their counter as index - self.returns.setdefault(cmd, {}) - - # now store the return - self.returns[cmd][index] = retval - - def error_handle(self, e): - '''error_handle - - This dummy handler will just print the current exception and go into - pdb - that could be very useful! - - Note - ---- - for demonstration purpose only. - - NEVER do this in production :) you will BLOCK sanity/regression - automated runs. - ''' - - print(e) - print('-' * 80) - - # go into pdb - pdb.set_trace() - - # re-raise the exception - # (default behavior) - raise - - - # now that we've defined a hook implementation - # let's hook an actual device. - # ----------------------------------------------------------- - - # assuming we have a testbed from somewhere - from pyats.topology import loader - testbed = loader.load('/path/to/testbed.yaml') - - # get the device and connect to it - device = testbed.devices['my-device'] - device.connect() - - # use our hook and hook onto the execute() service - hook = Tracker(device, 'execute') - # note that device.execute is actually device.connections['default'].execute - # as per connection manager integration with device objects. - # thus it's actually more accurate to hook onto the connection itself - # eg: - # hook = Tracker(device.connections['default'], 'execute') - - # from here onwards, all calls to device.execute() will be tracked - device.execute('show version') - device.execute('show ip interface brief') - - # the returned hook instance can be used to check the hook returns & etc - hook.counter - hook.returns - - # to disable the hook behavior, call the restore() api. - hook.restore() - # this will restore the original functionality and disable the hook diff --git a/docs/connections/index.rst b/docs/connections/index.rst index 4d63dd4..7ee5b31 100644 --- a/docs/connections/index.rst +++ b/docs/connections/index.rst @@ -11,5 +11,5 @@ integrates into the pyATS topology model. integration manager class - hook + wrapper sharing \ No newline at end of file diff --git a/docs/connections/wrapper.rst b/docs/connections/wrapper.rst new file mode 100644 index 0000000..f5a152c --- /dev/null +++ b/docs/connections/wrapper.rst @@ -0,0 +1,375 @@ +.. _service_wrapper:: + +Service Wrapper +=============== + +The Service Wrapper is a class designed to wrap various methods of a Connection +object with pre, post, and exception handlers, adding extra functionality to +existing Connection methods. It allows users to extend and customize the +behavior of specific Connection methods without modifying the original +implementation. + +Here are some typical use cases of service wrappers: + + - tracking the sequence/occurance of CLI command calls throughout a script + + - debug-logging the input arguments to, and output values from particular + services. + + - building a LRU cache based on script inputs and device states. + + - etc. + + +Usage +----- + +To use the Service Wrapper, follow these steps: + +1) Create a child class derived from the `pyats.connections.ServiceWrapper` +class. This child class will serve as the Service Wrapper for the desired +Connection methods. + +2) Set the `conn_type` and `service_name` of the child class to the Connection +type and service name that the Service Wrapper will be applied to. This will +typically be `unicon.Connection` and the name of the service method, such as +`execute` or `configure`. The `order` class variable can also be set to +determine the order in which the Service Wrappers will be applied. + +3) Define the conditions under which the Service Wrapper should be applied to +the service using the `applicable` method. + +4) (Optional) Implement the necessary methods in the child class to define pre, +post, and exception handling behavior. These methods will be executed at +different stages during the service call. + +5) (Optional) Use Testcase `Steps` to provide more robust reporting and +leverage the pyATS reporter functionality. + +6) (Optional) Configure CLI parser arguments in the child class using the +`configure_parser` method. This is used to enable easy integration with CLI +interfaces. + +.. note:: + + Error handlers can suppress an exception, and/or track/register it + internally. By default the built-in error handler will simply raise the + current exception. Developer can modify that to suppress the current + exception being handled, and return a fixed/altered result. + + +Service Wrapper Class +--------------------- + +The Service Wrapper base class provides several methods that can be overwritten +by the user to customize the behavior of the service call: + +`call_service` +`````````````` + +This method is responsible for calling the wrapped service. By default, it calls + the service and passes any arguments that were provided to it. It returns the + output of the service call, which can be utilized in the `post_service` method. + If an error occurs, it calls the `exception_service` method. This method can + be completely overloaded to change the behavior of the service call. + +.. code-block:: python + + def call_service(self, *args, **kwargs) -> Any: + """Call the service three times""" + ret_list = [] + for _ in range(3): + try: + ret_list.append(self.service(*args, **kwargs)) + except Exception as e: + logger.exception(f"Exception occurred: {e}") + return ret_list + +`exception_service` +``````````````````` + +The `exception_service` method is called if an exception occurs during the +service call inside the `call_service` method. It is an abstracted method that +will only run if the child class implements it. It can return anything to be +used in the `post_service` method. + +.. code-block:: python + + def exception_service(self, e: Exception, *args, **kwargs) -> Any: + logger.exception(f"Exception occurred: {e}") + return f'Exception occurred: {e}' + +`pre_service` +````````````` + +The `pre_service` method is called before the `call_service` method is executed. + It is an abstracted method that will only run if the child class implements it. + This method allows performing any necessary actions or setup before the actual + service call. + +.. code-block:: python + + def pre_service(self, *args, **kwargs) -> None: + logger.info(f"Running pre_service on {self.service_name}") + logger.info(f"{self.service_name} args: {args} kwargs: {kwargs}") + +`post_service` +`````````````` + +The `post_service` method is called after the `call_service` method is executed. + It is an abstracted method that will only run if the child class implements it. + This method is used to handle any post-processing actions after the service + call. It receives the output of the `call_service` method as an argument. + +.. code-block:: python + + def post_service(self, output: Any, *args, **kwargs) -> None: + logger.info(f"Running post_service on {self.service_name}") + logger.info(f"{self.service_name} output: {output}") + +`configure_parser` +`````````````````` + +The `configure_parser` method is called when the Service Wrapper is loaded. It +is used to configure CLI parser arguments, similar to an easypy plugin. This is +a classmethod that requires definition from the implementor. It takes in a +`parser` argument, which is an instance of the `argparse.ArgumentParser` class. + +.. code-block:: python + + @classmethod + def configure_parser(cls, parser: argparse.ArgumentParser) -> None: + parser.add_argument( + '--service-wrapper-arg', + dest='service_wrapper_arg', + action='store_true', + help='Service Wrapper argument', + ) + + return parser + +`applicable` +```````````` + +The `applicable` class method is used to determine whether the Service Wrapper +should be applied to the service. This is also a classmethod that requires +definition from the implementor. It takes in a `connection` argument, which is +an instance of the `pyats.connections.BaseConnection` class. It should return a +boolean value: `True` if the Service Wrapper should be applied, and `False` +otherwise. + +This is in addition to the default `conn_type` and `service_name` checks that +are done. This allows for more fine-grained control over which services the +Service Wrapper is applied to. For example, the Service Wrapper can be applied +to a specific device type, or only when a certain argument is passed to the +service. + +.. code-block:: python + + # Override applicable to check if the device is an IOSXE device + @classmethod + def applicable(cls, connection: BaseConnection, *args, **kwargs) -> bool: + """Ensure the device OS is iosxe and the service wrapper argument is passed""" + return connection.device.os == 'iosxe' + +Important Attributes +```````````````````` + +The Service Wrapper base class also provides several attributes that can be used + in the Service Wrapper methods: + +- `self.service` + - The service method that the Service Wrapper is applied to + - Note that this should be exclusively used to call the wrapper services. + You **cannot** call `self.execute` for example as this does not exist. +- `self.connection` + - The Connection object that the Service Wrapper is applied to + - Note that caution should be taken when calling wrapped attributes on the + connection object. It's possible to create an infinite loop if the wrapped + attribute is also wrapped by the Service Wrapper. +- `self.device` + - The device object that the Connection object is connected to +- `self.logger` + - The logger object that can be used to log messages specific to the Service + Wrapper +- `self.testcase` + - The testcase object that can be used to access testcase data + - This is the same testcase object that is passed to easypy plugins and has + access to testcase data through `self.testcase.parameters` +- `self.args` + - The arguments as defined in the `configure_parser` method + +Class Variables +``````````````` + +In addition to the methods, the Service Wrapper base class also provides several + class variables that must be set to define which service the Service Wrapper + will be applied to: + +- `conn_type` + - The Connection type that the Service Wrapper will be applied to. Options + include + + .. code-block:: python + + # This is a catch-all for all Connection types + pyats.connections.BaseConnection + + # This is the standard unicon connection + unicon.Connection + + # Used for rest connections + rest.connector.Rest + + # Used for yang connections + yang.connector.Gnmi + yang.connector.Netconf + +- `service_name` + - The service the wrapper will be used on. This will be the name of the + service method, such as `execute` or `configure` + +- `order` + - This is an optional variable. It's is used to determine the order in which + the Service Wrappers will be applied. It is an integer value, with higher + values being applied first. The default value is `0`. + +Examples +-------- + +Execute Service Wrapper - IOSXE Device +`````````````````````````````````````` + +This is an example of a service wrapper for wrapping the execute service on an +IOSXE device + +.. note:: This example wrapper will run for ALL IOSXE devices when this wrapper + script is installed. If this wrapper is installed in a shared environment, + be aware that it affects all user jobs and any IOSXE devices in use. + +.. code-block:: python + + import unicon + from pyats.connections import ServiceWrapper + + class ExampleWrapper(ServiceWrapper): + conn_type = unicon.Connection + service_name = 'execute' + + @classmethod + def configure_parser(cls, parser) -> None: + parser.add_argument( + '--service-wrapper-arg', + dest='service_wrapper_arg', + action='store_true', + help='Service Wrapper argument', + ) + + return parser + + @classmethod + def applicable(cls, connection, *args, **kwargs) -> bool: + return connection.device.os == 'iosxe' + + def pre_service(self, *args, **kwargs) -> None: + self.logger.info(f"Running command: {args[0]} on {self.device.name}") + + def post_service(self, output, *args, **kwargs) -> None: + self.logger.info(f"Output: {output}") + + def call_service(self, *args, **kwargs) -> Any: + try: + self.logger.info(f"Calling service: {self.service_name}") + return self.service(*args, **kwargs) + except Exception as e: + return self.exception_service(e, *args, **kwargs) + + def exception_service(self, e, *args, **kwargs): + self.logger.exception(f"Exception occurred: {e}") + return f'Exception occurred: {e}' + +Steps +----- + +Inside of each service wrapper method you are able to pass a `steps` argument +that will automatically pick up the Testcase's current `steps` object, which +allows for use of the context manager style of reporting, failing, and passing +a test. + +.. code-block:: python + + with steps.start() as step: + step.passed('Passed') + +This can be used in any of the four service wrapper methods. + +.. code-block:: python + + from pyats.connections import ServiceWrapper + + class ExampleWrapper(ServiceWrapper): + @classmethod + def applicable(cls, connection, *args, **kwargs) -> bool: + return True + + def pre_service(self, steps, *args, **kwargs) -> None: + with steps.start('Pre Service Step') as step: + step.passed('Sucessfully ran pre service step') + + def post_service(self, output, steps, *args, **kwargs) -> None: + with steps.start('Post Service Step') as step: + step.passed('Sucessfully ran post service step') + + def call_service(self, steps, *args, **kwargs) -> None: + with steps.start('Call Service Step') as step: + step.passed('Sucessfully ran call service step') + + def exception_service(self, e, steps, *args, **kwargs) -> None: + with steps.start('Exception Service Step') as step: + step.passed('Sucessfully ran exception service step') + +.. note:: The `steps` argument is only filled when the service wrapper is run in + the context of a Testcase. If no Testcase is found, the `steps` argument + will be `None`. Keep this in mind if your service wrapper is used in a + standalone context with no Testcase. + +Discovery +--------- + +There are two methods to enable pyATS to discover service wrappers. The first +method is to configure the service wrapper in the pyats configuration file. The +second method is to use an entry point. + +Configuration Method +```````````````````` + +Once the service wrapper is created, you can utilize it by adding it to the +pyats configuration file. You can read up on how to configure that +:ref:`here. ` + +.. code-block:: ini + + [service_wrapper] + example_wrapper = path.to.module:ExampleWrapper + +Entrypoint Method +````````````````` + +Additionally, you can utilize it by adding it as an entry +point in your package's setup file through the `pyats.connections.wrapper` +entry point descriptor. This enables the service wrapper to be called and +employed within the context of your package, facilitating seamless integration +and utilization of the wrapped functionalities. + +.. code-block:: python + + setup( + ..., + + # console entry point + entry_points = { + 'pyats.connections.wrapper': [ + 'example_wrapper = path.to.path:ExampleWrapper' + ] + } + ) \ No newline at end of file diff --git a/docs/easypy/email.rst b/docs/easypy/email.rst index 940dda0..6686f75 100644 --- a/docs/easypy/email.rst +++ b/docs/easypy/email.rst @@ -51,7 +51,20 @@ The following describes the default email report content. Note that fields in TOTAL : {runtime.job.results[total]} - Success Rate : {runtime.job.results[success_rate]:.02f} % + Success Rate : {runtime.job.results[success_rate]:.02f} + + Section Stats + Passed : {runtime.job.section_results[passed]} + Passx : {runtime.job.section_results[passx]} + Failed : {runtime.job.section_results[failed]} + Aborted : {runtime.job.section_results[aborted]} + Blocked : {runtime.job.section_results[blocked]} + Skipped : {runtime.job.section_results[skipped]} + Errored : {runtime.job.section_results[errored]} + + TOTAL : {runtime.job.section_results[total]} + + Section Success Rate : {runtime.job.section_results[success_rate]:.02f} +------------------------------------------------------------------------------+ | Task Result Summary | @@ -91,6 +104,24 @@ host, update the following fields in pyATS :ref:`pyats_configuration`'s Report Customization -------------------- +The email and job summary report includes Overall Stats which is based on the +count of CommonSetup, CommonCleanup, Testcase, Trigger and Verification +classes defined in test scripts. The report also includes Section Stats that +summarize SubSection, SetupSection, CleanupSection and TestSection stats. + +The section reporting can be changed by updating the `report.sections` +configuration to define which sections should be counted for reporting purposes. + +For example, to include only TestSections (decorated with `@aetest.test`), Setup +(`aetest.setup`) and Cleanup (`@aetest.cleanup`) sections, set `report.sections` +as below. The values for the sections are space separated. + +.. code-block:: ini + + # report configuration + [report] + sections = TestSection SetupSection CleanupSection + Easypy email notification reports are fully customizable, allowing users to attach custom information to the email report body. @@ -248,8 +279,42 @@ at any time prior to calling the send() method. - **to_email**: A list or tuple of recipient addresses. - **subject**: The subject line of the email. - **body**: The body text. This should be a plain text message. - - **attachments**: A list of attachments to put on the message. These can be - either email.MIMEBase.MIMEBase instances, or (filename, content, mimetype) - triples - currently only supports MIMEText. + - **attachments**: A list of attachments to put on the message. Currently only supports MIMEText. - **html_email**: flag to enable alternative HTML email format. - **html_body**: Body in HTML format. + +.. code-block:: python + + # Example + # ------- + # + # Sending email from pyATS + + # import EmailMsg class + from pyats.utils.email import EmailMsg + + # Create email message object + mail = EmailMsg( + from_email=email_from_address, + to_email=email_to_address, + subject=email_subject, + body=email_body) + + # send email + mail.send() + + # If you want to send HTML email: + mail = EmailMsg( + from_email=email_from_address, + to_email=email_to_address, + subject=email_subject, + html_email=True, + html_body=html_body) + + # You can also add attachments: + mail = EmailMsg( + from_email=email_from_address, + to_email=email_to_address, + subject=email_subject, + body=email_body, + attachments=['/path/to/file']) diff --git a/docs/easypy/jobfile.rst b/docs/easypy/jobfile.rst index 53c6670..857fcb3 100644 --- a/docs/easypy/jobfile.rst +++ b/docs/easypy/jobfile.rst @@ -242,18 +242,24 @@ Task Class ``Task`` class objects represent the task/testscript being executed in a child process. It is a subclass of Python ``multiprocessing.Process`` class, and -always uses ``multiproessing.get_context('fork')`` to fork and create child -processes. +always uses ``multiprocessing.get_context('fork')`` to fork and create child +processes. The ``gTask`` class object is used for Genie Tasks. .. csv-table:: Task Class Arguments :header: "Argument", "Description" ``testscript``, "testscript to be run in this task" - ``taskid``, "unique task id (defaults to ``Task-#`` where # is an - incrementing number)" + ``taskid``, "unique task id (defaults to ``Task-#`` where # is an incrementing number)" ``runtime``, "easypy runtime object" - ``kwargs``, "any other keyword-arguments to be passed to the testscript - as script parameters" + ``clean_files``, "List of clean files, specific to this task (optional)" + ``logical_testbed_file``, "Path to logical testbed file, specific to this task (optional)" + ``kwargs``, "any other keyword-arguments to be passed to the testscript as script parameters" + +For Genie tasks, the `gTask` class can be used. No testscript should be specified for Genie tasks. + +The ``clean_files`` and ``logical_testbed_File`` arguments are optional arguments +that can be passed if the task uses task specific clean. By default, the job level +clean arguments are used. Like its parent ``Process`` class, instantiating a ``Task`` object does not create the actual child process: the class constructor only sets internal states @@ -350,6 +356,32 @@ each task process. # raise exception raise TimeoutError('Not all tasks finished in 5 minutes!') +Example for Genie tasks with gTask. The ``gTask`` class is imported from the `genie.harness.main` module. + +.. code-block:: python + + # Example + # ------- + # + # job file tasks using gTask() api + + from genie.harness.main import gTask + + def main(runtime): + + # using Task class to create a task object + task_1 = gTask(trigger_datafile='trigger_data.yaml', + config_datafile='config_data.yaml', + subsection_datafile='subsection_data.yaml', + trigger_uids='TestBgp', + taskid='task1') + + # start the task + task_1.start() + + # wait for a max runtime of 60*5 seconds = 5 minutes + task_1.wait(60*5) + Easypy expects all tasks to be finished/terminated when ``main()`` scope is exited (eg, the jobfile finished execution). Therefore, all tasks created and started using ``Task`` class should always be waited for using ``wait()``, and diff --git a/docs/index.rst b/docs/index.rst index 543a8e6..43569cc 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -23,6 +23,7 @@ studies and more. :maxdepth: 1 :caption: Main Components + aereport/index aetest/index easypy/index topology/index diff --git a/docs/manifest/introduction.rst b/docs/manifest/introduction.rst index a4706d6..053070c 100644 --- a/docs/manifest/introduction.rst +++ b/docs/manifest/introduction.rst @@ -48,7 +48,7 @@ the manifest. Currently, the supported types for the manifest are: * easypy -Only suported script types have an execution runtime that allows +Only supported script types have an execution runtime that allows the manifest to execute the script. @@ -80,11 +80,13 @@ The internal argument structure is translated to the command line argument strin * Arguments may explicitly define dash syntax, e.g `"-key": value` * Argument values are quoted using double quotes, e.g. `val1` will translate to `"val1"` * Arguments specified as a list will translate to `--key "val1" "val2"` - * If the value is `*N`, repeat the argument key N number of times + * If the value is `*N`, repeat the argument key N number of times (e.g. `"-v": "*3"` translates to `-v -v -v`) * If the value is a boolean, leave out the value and only add - the key to the argument string, e.g. `flag: True` translates to `--flag`. - * If the boolean needs to be explicitly added to the argument string, the value - must be explicitly specified as a string, e.g. `key: "True"` + the key to the argument string, e.g. `flag: True` translates to `--flag`. Note: + if the boolean needs to be explicitly added to the argument string, the value + must be explicitly specified as a string, e.g. `key: "True"` (not as a boolean value). + See below for overriding boolean arguments. + * If the `meta` argument is used on the command line, it will be prepended as an additional meta argument. For example, the script arguments defined in the manifest could look like this: @@ -110,6 +112,46 @@ For example running the manifest execution with the above arguments and adding t $ pyats validate manifest job.tem --profile local --testbed-file testbed2.yaml +**Meta argument handling** + +If the `meta` argument is used on the command line, it will be prepended +as an additional meta argument. Note, the value for the `meta` argument provided +via a *profile* argument will override the default value (same as for any other argument). + +.. code-block:: yaml + + arguments: + meta: key1=value1 + +.. code-block:: + + $ pyats validate manifest job.tem --meta key2=value2 + +The above will result in the following command line arguments to be used: + +.. code-block:: + + pyats run job job.py --meta key2=value2 --meta key1=value1 + + +**Overriding boolean arguments** + +You can override boolean arguments by specifying the boolean string value after the argument +on the command line, i.e. `"False"` or `"True"`. + +With below example, the ``no-mail: True`` argument specified in the manifest can be overriden +by specifying the argument on the manifest command line with value `False`. This combination +will result in the `--no-mail` argument *not* to be added to the `pyats run job` command. + +.. code-block:: yaml + + arguments: + no-mail: True + +.. code-block:: shell + + $ pyats validate manifest job.tem --no-mail False + runtimes ~~~~~~~~ diff --git a/docs/topology/creation.rst b/docs/topology/creation.rst index 61ada47..201ded3 100644 --- a/docs/topology/creation.rst +++ b/docs/topology/creation.rst @@ -94,216 +94,8 @@ unanimous for all. Testbed File Markups -------------------- -Another advantage of using testbed files is to leverage the built-in markup -feature. Whereas standard YAML format does not allow variable substitution and -references, ``topology.loader`` effectively added this using specific syntax -(markups) similar to the Django template language. +See :ref:`yaml_file_markup` -.. code-block:: text - - # Syntax - # ------ - # - # YAML markup syntax - - # basic syntax - # ------------ - # %{..<...>} - # %INTF{logical_interface_name} - # %ENV{environment_variable_name} - # %CALLABLE{path_to_callable} - # %CALLABLE{path_to_callable(param1,param2,param3)} - # %INCLUDE{yaml_file_path} - # %ASK{optional prompt text} - # %ENC{encoded text} - # %ENC{encoded text, prefix=x} - # %CLI{cli_argument_name} - # - # - use %{ } to denote the begin and end of a markup block - # - use . to separate reference path - # - use 'self' as first word to reference current device - # - The %INTF{ } form causes the logical interface name to be - # replaced with the actual interface name from the - # device's topology block. - # - The %ENV{ } form causes the environment variable name to be - # replaced with the actual environment value from the os. - # - The %CALLABLE{ } form causes the callable to be replaced with the - # actual return value from the callable. All defined parameters - # will be passed to the callable. - # - The %INCLUDE{ } form causes the yaml file path to be replaced - # with the actual content of the yaml file. - # - The %ASK{ } form causes the user to be prompted to enter information - # manually. - # - The %ENC{ } form causes an encoded string to be replaced with a - # decoded string or secret string which supports decoding. - # - The %CLI{ } form replaces the variable name with the value provided - # from the command line argument. If no command line argument was - # provided for this variable, the value will be an empty string. - # Supports single and double dash argument style. - - # reference to current device name - %{self} - - # reference to attributes within current device - %{self.x.y.z} - - # reference to logical interface within current device - # (replaced with actual interface name) - %INTF{logical_interface_name} - - # reference to arbitrary attribute within this YAML file - %{a.b.c} - - # reference to environment variable from the os - # (replaced with actual environment variable name) - %ENV{environment_variable_name} - - # reference to callable without parameter - # (replaced with actual path to callable) - %CALLABLE{path.to.callable} - - # reference to callable with parameters param1, param2 and param3 - # (replaced with actual path to callable) - %CALLABLE{path.to.callable(param1,param2,param3)} - - # reference to content from other YAML file - # (replaced with actual path to YAML file) - %INCLUDE{yaml_file_path} - - # prompt user to enter string content manually - %ASK{optional prompt text} - - # Reference to text encoded with "pyats secret encode" command - # Encoded credential passwords are substituted by secret strings. - # Other encoded references are substituted with their decoded string. - # See secret strings documentation for details. - %ENC{} - - # Reference to text encoded with "pyats secret encode --prefix x" command. - # Encoded credential passwords are substituted by secret strings. - # Other encoded references are substituted with their decoded string. - # See secret strings documentation for details. - %ENC{, prefix=x} - - # Reference to "some_arg" will be replaced by "some_value" if - # the command line "pyats run job --some_arg some_value" is used. - %CLI{some_arg} - - # If the command line argument is provided without a value, - # the value is set to boolean 'True'. The following command line - # sets the value for "some_flag" to True. - # "pyats run job --some_flag" - %CLI{some_flag} - - # If the command line argument has multiple values, - # the variable is replaced with a list of values. - # The following command line argument creates a list - # of values in place of the devices variable. - # "pyats run job --devices R1 R2" - %CLI{devices} - - # If the command line argument contains a number value, - # either integer or float, the variable is converted from - # a string to an integer or float. - # "pyats run job --retries 3" - %CLI{retries} - -.. note:: - - Make sure to enclose your markup in quotes if it occurs directly - after a colon. For example:: - - testbed: - name: my_testbed - - passwords: - enable: lab - line: "%{testbed.passwords.enable}" - tacacs: "%{testbed.passwords.enable}" - tacacs: - username: admin - -YAML itself does not distinguish the markups from regular text (strings). -Before the creation of testbed objects, the loader walks through the generated -data and replaces all markup languages with referenced data. -Any syntax outside of the above is neither recognized nor processed. - -.. code-block:: yaml - - # Example - # ------- - # - # yaml testbed using markup - # notice how markups were used as information references. - devices: - example_device: - type: "%CALLABLE{mylib.get_device_type}" - connections: - a: - protocol: telnet - ip: "1.1.1.1" - port: 2001 - alt: - protocol: telnet - ip: "%{self.clean.mgt_itf.ipv4.address}" - - dynamic_device: "%CALLABLE{mylib.create_device(2.2.2.2)}" - topology: - example_device: - interfaces: - Ethernet4/6: - alias: my_logical_interface - link: link-x - type: "%ENV{DEFAULT_INTERFACE_TYPE}" - dynamic_device: "%INCLUDE{/path/to/dynamic/generated/device/interfaces/file}" - - -Testbed file can be broken down in multiple yaml files with the extend key. -Each file can represent a subset of the main testbed file. - - -Let's say this file is named tb1.yaml - -.. code-block:: yaml - - devices: - xr-1: - connections: - cli: - ip: 10.1.1.1 - protocol: ssh - credentials: - default: - password: cisco - username: cisco - enable: - password: cisco - os: iosxr - type: iosxr - - -And this file is named tb2.yaml - -.. code-block:: yaml - - extends: tb1.yaml - devices: - xr-2: - connections: - cli: - ip: 10.2.2.2 - protocol: ssh - credentials: - default: - password: cisco - username: cisco - enable: - password: cisco - os: iosxr - type: iosxr - -Now at run time, you can provide the tb2.yaml, which will merge tb1.yaml and -tb2.yaml together to create a merged testbed. Manual Creation --------------- diff --git a/docs/topology/schema.rst b/docs/topology/schema.rst index f531722..ad3ef6f 100644 --- a/docs/topology/schema.rst +++ b/docs/topology/schema.rst @@ -220,8 +220,8 @@ Production YAML Schema peripherals: # device hardware block # may contain anything describing peripherals - # connected to the device. - # currently supported devices are terminal servers + # connected to the device. + # currently supported devices are terminal servers # and power cyclers. # (optional) @@ -273,6 +273,9 @@ Production YAML Schema # (default: None - let the connection class decide) # (optional) + fallback_credentials: # list of the fallback credentials to be used for + # the connections in the testbed.(optional) + connections: # a list of subconnections for a multi-console # device. # Supported by unicon connector implementation. @@ -311,6 +314,9 @@ Production YAML Schema port: # port to connect to # (optional) + fallback_credentials: # list of the fallback credentials for this + # connection.(optional) + credentials: # credential details specific to this connection # (optional) diff --git a/docs/utilities/index.rst b/docs/utilities/index.rst index 895bd42..eeacdd2 100644 --- a/docs/utilities/index.rst +++ b/docs/utilities/index.rst @@ -11,5 +11,6 @@ Utilities file_transfer_utilities file_transfer_server import_utils + yaml_markup .. sectionauthor:: Myles Dear diff --git a/docs/utilities/yaml_markup.rst b/docs/utilities/yaml_markup.rst new file mode 100644 index 0000000..d2178c5 --- /dev/null +++ b/docs/utilities/yaml_markup.rst @@ -0,0 +1,366 @@ + +.. _yaml_file_markup: + +YAML File Markups +================= + +The pyATS YAML loader, which is used in several places including the testbed +loader, supports pyATS specific YAML markup. + +Whereas standard YAML format does not allow variable substitution and +references, ``pyats.utils.yaml.Loader`` effectively added this using specific +syntax (markups) similar to the Django template language. + +Reference +--------- + +.. code-block:: text + + # Syntax + # ------ + # + # YAML markup syntax + + # basic syntax + # ------------ + # %{..<...>} + # %{..<...>.keys()} + # %INTF{logical_interface_name} + # %ENV{environment_variable_name} + # %CALLABLE{path_to_callable} + # %CALLABLE{path_to_callable(param1,param2,param3)} + # %CALLABLE{path_to_callable(param1='val1',param2='val2')} + # %INCLUDE{yaml_file_path} + # %ASK{optional prompt text} + # %ENC{encoded text} + # %ENC{encoded text, prefix=x} + # %CLI{cli_argument_name} + # %CLI{another_cli_arg, default=} + # %CLI{another_list, default=[,]} + # %EXTEND_LIST{key} + # %EXTEND_LIST{path.to.value1,path.to.value2} + # + # - use %{ } to denote the begin and end of a markup block + # - use . to separate reference path + # - use 'self' as first word to reference current device + # - use '.keys()' to get the key values for a path + # - The %INTF{ } form causes the logical interface name to be + # replaced with the actual interface name from the + # device's topology block. + # - The %ENV{ } form causes the environment variable name to be + # replaced with the actual environment value from the os. + # - The %CALLABLE{ } form causes the callable to be replaced with the + # actual return value from the callable. All defined parameters + # will be passed to the callable. + # - The %INCLUDE{ } form causes the yaml file path to be replaced + # with the actual content of the yaml file. + # - The %ASK{ } form causes the user to be prompted to enter information + # manually. + # - The %ENC{ } form causes an encoded string to be replaced with a + # decoded string or secret string which supports decoding. + # - The %CLI{ } form replaces the variable name with the value provided + # from the command line argument. If no command line argument was + # provided for this variable, the value will be an empty string. + # Supports single and double dash argument style. A default value + # can be specified using `, default=` syntax. A list can be specified + # as default value. + # - The %EXTEND_LIST{ } form can be used for keys to extend a list + # from another YAML file. The same syntax can also be used to create + # a value by extending one or more list references. + + +Markup Examples +--------------- + +.. code-block:: text + + # reference to current device name + %{self} + + # reference to attributes within current device + %{self.x.y.z} + + # reference to logical interface within current device + # (replaced with actual interface name) + %INTF{logical_interface_name} + + # reference to arbitrary attribute within this YAML file + %{a.b.c} + + # reference to the list of keys of this attribute within this YAML file + %{d.e.keys()} + + # reference to environment variable from the os + # (replaced with actual environment variable name) + %ENV{environment_variable_name} + + # reference to callable without parameter + # (replaced with actual path to callable) + %CALLABLE{path.to.callable} + + # reference to callable with parameters param1, param2 and param3 + # (replaced with actual path to callable) + %CALLABLE{path.to.callable(param1,param2,param3)} + + # reference to callable with paramter param1 and + # kwarg style parameter param2 + %CALLABLE{path.to.callable(param1, param2='val1')} + + # reference to content from other YAML file + # (replaced with actual path to YAML file) + %INCLUDE{yaml_file_path} + + # prompt user to enter string content manually + %ASK{optional prompt text} + + # Reference to text encoded with "pyats secret encode" command + # Encoded credential passwords are substituted by secret strings. + # Other encoded references are substituted with their decoded string. + # See secret strings documentation for details. + %ENC{} + + # Reference to text encoded with "pyats secret encode --prefix x" command. + # Encoded credential passwords are substituted by secret strings. + # Other encoded references are substituted with their decoded string. + # See secret strings documentation for details. + %ENC{, prefix=x} + + # Reference to "some_arg" will be replaced by "some_value" if + # the command line "pyats run job --some_arg some_value" is used. + %CLI{some_arg} + + # If the command line argument is provided without a value, + # the value is set to boolean 'True'. The following command line + # sets the value for "some_flag" to True. + # "pyats run job --some_flag" + %CLI{some_flag} + + # If the command line argument has multiple values, + # the variable is replaced with a list of values. + # The following command line argument creates a list + # of values in place of the devices variable. + # "pyats run job --devices R1 R2" + %CLI{devices} + + # If the command line argument contains a number value, + # either integer or float, the variable is converted from + # a string to an integer or float. + # "pyats run job --retries 3" + %CLI{retries} + + # A default value can be specified for the %CLI markup. + %CLI{another_flag, default=12} + + # A default value can be a list + %CLI{another_flag, default=[1,2]} + +.. note:: + + Make sure to enclose your markup in quotes if it occurs directly + after a colon. For example:: + + testbed: + name: my_testbed + + passwords: + enable: lab + line: "%{testbed.passwords.enable}" + tacacs: "%{testbed.passwords.enable}" + tacacs: + username: admin +.. note:: + + Make sure to enclose strings with % sign in quotes + in the yaml file. For example:: + + testbed: + name: my_testbed + + credentials: + password: "%ASK{Your password}" + +YAML itself does not distinguish the markups from regular text (strings). +Before the creation of testbed objects, the loader walks through the generated +data and replaces all markup languages with referenced data. +Any syntax outside of the above is neither recognized nor processed. + + +Testbed YAML Examples +--------------------- + +.. code-block:: yaml + + # Example + # ------- + # + # yaml testbed using markup + # notice how markups were used as information references. + devices: + example_device: + type: "%CALLABLE{mylib.get_device_type}" + connections: + a: + protocol: telnet + ip: "1.1.1.1" + port: 2001 + alt: + protocol: telnet + ip: "%{self.clean.mgt_itf.ipv4.address}" + + dynamic_device: "%CALLABLE{mylib.create_device(2.2.2.2)}" + topology: + example_device: + interfaces: + Ethernet4/6: + alias: my_logical_interface + link: link-x + type: "%ENV{DEFAULT_INTERFACE_TYPE}" + dynamic_device: "%INCLUDE{/path/to/dynamic/generated/device/interfaces/file}" + + +Testbed file can be broken down in multiple yaml files with the extend key. +Each file can represent a subset of the main testbed file. + + +Let's say this file is named tb1.yaml + +.. code-block:: yaml + + devices: + xr-1: + connections: + cli: + ip: 10.1.1.1 + protocol: ssh + credentials: + default: + password: cisco + username: cisco + enable: + password: cisco + os: iosxr + type: iosxr + + +And this file is named tb2.yaml + +.. code-block:: yaml + + extends: tb1.yaml + devices: + xr-2: + connections: + cli: + ip: 10.2.2.2 + protocol: ssh + credentials: + default: + password: cisco + username: cisco + enable: + password: cisco + os: iosxr + type: iosxr + +Now at run time, you can provide the tb2.yaml, which will merge tb1.yaml and +tb2.yaml together to create a merged testbed. + +EXTEND_LIST usage examples +-------------------------- + +`%EXTEND_LIST` markup can be used in two ways: as a key markup or as a value markup. + +1. Example EXTEND_LIST usage for key markup. + +Example YAML file to be extended: + +.. code-block:: yaml + + parameters: + sections: [a, b] + +YAML file extending the file above: + +.. code-block:: yaml + + extends: a.yaml + + parameters: + "%EXTEND_LIST{sections}": [c] + +Example code loading an extended YAML file: + +.. code-block:: python + + from pyats.utils.yaml import Loader + loader = Loader(enable_extensions=True) + data = loader.load('b.yaml') + print(data) + +The output from above script is show below. As you can see, +the list data was extended from [a, b] to [a, b, c]. + +.. code-block:: text + + {'parameters': {'sections': ['a', 'b', 'c']}} + + +2. Example EXTEND_LIST usage for values. + +It's also possible to created a list from one or more other lists using +the EXTEND_LIST markup with one or more references to list values. + +.. code-block:: yaml + + parameters: + base_config: + CE1: + bgp: + address_families: + ipv4: + neighbors: + 1.1.1.1: {} + 1.1.1.2: {} + ipv6: + neighbors: + - 1::1 + - 1::2 + + CE1_neighbors: "%EXTEND_LIST{parameters.base_config.CE1.bgp.address_families.ipv4.neighbors.keys(),parameters.base_config.CE1.bgp.address_families.ipv6.neighbors}" + + +The output from above data after loading is shown below. The single lists of +neighbors is created by combining the two lists using their markup reference. + +.. code-block:: text + + { + "parameters": { + "base_config": { + "CE1": { + "bgp": { + "address_families": { + "ipv4": { + "neighbors": { + "1.1.1.1": {}, + "1.1.1.2": {} + } + }, + "ipv6": { + "neighbors": [ + "1::1", + "1::2" + ] + } + } + } + } + }, + "CE1_neighbors": [ + "1.1.1.1", + "1.1.1.2", + "1::1", + "1::2" + ] + } + }