diff options
Diffstat (limited to 'collections-debian-merged/ansible_collections/cisco/nso')
57 files changed, 6402 insertions, 0 deletions
diff --git a/collections-debian-merged/ansible_collections/cisco/nso/.github/workflows/ansible-test.yml b/collections-debian-merged/ansible_collections/cisco/nso/.github/workflows/ansible-test.yml new file mode 100644 index 00000000..8255db11 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/.github/workflows/ansible-test.yml @@ -0,0 +1,112 @@ +# README FIRST +# 1. replace "NAMESPACE" and "COLLECTION_NAME" with the correct name in the env section (e.g. with 'community' and 'mycollection') +# 2. If you don't have unit tests remove that section +# 3. If your collection depends on other collections ensure they are installed, see "Install collection dependencies" +# If you need help please ask in #ansible-devel on Freenode IRC + +name: CI +on: + # Run CI against all pushes (direct commits, also merged PRs), Pull Requests + push: + pull_request: + # Run CI once per day (at 06:00 UTC) + # This ensures that even if there haven't been commits that we are still testing against latest version of ansible-test for each ansible-base version + schedule: + - cron: '0 6 * * *' +env: + NAMESPACE: cisco + COLLECTION_NAME: nso + +jobs: + +### +# Sanity tests (REQUIRED) +# +# https://docs.ansible.com/ansible/latest/dev_guide/testing_sanity.html + + sanity: + name: Sanity (Ⓐ${{ matrix.ansible }}) + strategy: + matrix: + ansible: + # It's important that Sanity is tested against all stable-X.Y branches + # Testing against `devel` may fail as new tests are added. + # - stable-2.9 # Only if your collection supports Ansible 2.9 + - stable-2.10 + - devel + runs-on: ubuntu-latest + steps: + + # ansible-test requires the collection to be in a directory in the form + # .../ansible_collections/${{env.NAMESPACE}}/${{env.COLLECTION_NAME}}/ + + - name: Check out code + uses: actions/checkout@v2 + with: + path: ansible_collections/${{env.NAMESPACE}}/${{env.COLLECTION_NAME}} + + - name: Set up Python + uses: actions/setup-python@v2 + with: + # it is just required to run that once as "ansible-test sanity" in the docker image + # will run on all python versions it supports. + python-version: 3.8 + + # Install the head of the given branch (devel, stable-2.10) + - name: Install ansible-base (${{ matrix.ansible }}) + run: pip install https://github.com/ansible/ansible/archive/${{ matrix.ansible }}.tar.gz --disable-pip-version-check + + # run ansible-test sanity inside of Docker. + # The docker container has all the pinned dependencies that are required + # and all python versions ansible supports. + - name: Run sanity tests + run: ansible-test sanity --docker -v --color + working-directory: ./ansible_collections/${{env.NAMESPACE}}/${{env.COLLECTION_NAME}} + +### +# Unit tests (OPTIONAL) +# +# https://docs.ansible.com/ansible/latest/dev_guide/testing_units.html + + units: + runs-on: ubuntu-latest + name: Units (Ⓐ${{ matrix.ansible }}) + strategy: + # As soon as the first unit test fails, cancel the others to free up the CI queue + fail-fast: true + matrix: + ansible: + # - stable-2.9 # Only if your collection supports Ansible 2.9 + - stable-2.10 + - devel + + steps: + - name: Check out code + uses: actions/checkout@v2 + with: + path: ansible_collections/${{env.NAMESPACE}}/${{env.COLLECTION_NAME}} + + - name: Set up Python + uses: actions/setup-python@v2 + with: + # it is just required to run that once as "ansible-test units" in the docker image + # will run on all python versions it supports. + python-version: 3.8 + + - name: Install ansible-base (${{ matrix.ansible }}) + run: pip install https://github.com/ansible/ansible/archive/${{ matrix.ansible }}.tar.gz --disable-pip-version-check + + # Run the unit tests + - name: Run unit test + run: ansible-test units -v --color --docker --coverage + working-directory: ./ansible_collections/${{env.NAMESPACE}}/${{env.COLLECTION_NAME}} + + # ansible-test support producing code coverage date + - name: Generate coverage report + run: ansible-test coverage xml -v --requirements --group-by command --group-by version + working-directory: ./ansible_collections/${{env.NAMESPACE}}/${{env.COLLECTION_NAME}} + + # See the reports at https://codecov.io/gh/GITHUBORG/REPONAME + - uses: codecov/codecov-action@v1 + with: + fail_ci_if_error: false diff --git a/collections-debian-merged/ansible_collections/cisco/nso/.gitignore b/collections-debian-merged/ansible_collections/cisco/nso/.gitignore new file mode 100644 index 00000000..c722adee --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/.gitignore @@ -0,0 +1,393 @@ +# Created by https://www.gitignore.io/api/git,linux,pydev,python,windows,pycharm+all,jupyternotebook,vim,webstorm,emacs,dotenv +# Edit at https://www.gitignore.io/?templates=git,linux,pydev,python,windows,pycharm+all,jupyternotebook,vim,webstorm,emacs,dotenv + +### dotenv ### +.env + +### Emacs ### +# -*- mode: gitignore; -*- +*~ +\#*\# +/.emacs.desktop +/.emacs.desktop.lock +*.elc +auto-save-list +tramp +.\#* + +# Org-mode +.org-id-locations +*_archive + +# flymake-mode +*_flymake.* + +# eshell files +/eshell/history +/eshell/lastdir + +# elpa packages +/elpa/ + +# reftex files +*.rel + +# AUCTeX auto folder +/auto/ + +# cask packages +.cask/ +dist/ + +# Flycheck +flycheck_*.el + +# server auth directory +/server/ + +# projectiles files +.projectile + +# directory configuration +.dir-locals.el + +# network security +/network-security.data + + +### Git ### +# Created by git for backups. To disable backups in Git: +# $ git config --global mergetool.keepBackup false +*.orig + +# Created by git when using merge tools for conflicts +*.BACKUP.* +*.BASE.* +*.LOCAL.* +*.REMOTE.* +*_BACKUP_*.txt +*_BASE_*.txt +*_LOCAL_*.txt +*_REMOTE_*.txt + +#!! ERROR: jupyternotebook is undefined. Use list command to see defined gitignore types !!# + +### Linux ### + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### PyCharm+all ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### PyCharm+all Patch ### +# Ignores the whole .idea folder and all .iml files +# See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360 + +.idea/ + +# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 + +*.iml +modules.xml +.idea/misc.xml +*.ipr + +# Sonarlint plugin +.idea/sonarlint + +### pydev ### +.pydevproject + +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# Mr Developer +.mr.developer.cfg +.project + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +### Vim ### +# Swap +[._]*.s[a-v][a-z] +[._]*.sw[a-p] +[._]s[a-rt-v][a-z] +[._]ss[a-gi-z] +[._]sw[a-p] + +# Session +Session.vim +Sessionx.vim + +# Temporary +.netrwhist +# Auto-generated tag files +tags +# Persistent undo +[._]*.un~ + +### WebStorm ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff + +# Generated files + +# Sensitive or high-churn files + +# Gradle + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake + +# Mongo Explorer plugin + +# File-based project format + +# IntelliJ + +# mpeltonen/sbt-idea plugin + +# JIRA plugin + +# Cursive Clojure plugin + +# Crashlytics plugin (for Android Studio and IntelliJ) + +# Editor-based Rest Client + +# Android studio 3.1+ serialized cache file + +### WebStorm Patch ### +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 + +# *.iml +# modules.xml +# .idea/misc.xml +# *.ipr + +# Sonarlint plugin +.idea/**/sonarlint/ + +# SonarQube Plugin +.idea/**/sonarIssues.xml + +# Markdown Navigator plugin +.idea/**/markdown-navigator.xml +.idea/**/markdown-navigator/ + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# End of https://www.gitignore.io/api/git,linux,pydev,python,windows,pycharm+all,jupyternotebook,vim,webstorm,emacs,dotenv + +# vsCode +.vscode +.DS_Store + +# Ansible Collection tarball +cisco-nso-*.tar.gz
\ No newline at end of file diff --git a/collections-debian-merged/ansible_collections/cisco/nso/CHANGELOG.rst b/collections-debian-merged/ansible_collections/cisco/nso/CHANGELOG.rst new file mode 100644 index 00000000..0d10e4b7 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/CHANGELOG.rst @@ -0,0 +1,50 @@ +========================================== +Cisco NSO Ansible Collection Release Notes +========================================== + +.. contents:: Topics + + +v1.0.3 +====== + +Minor Changes +------------- + +- nso_action can now handle YANG model choices as input parameters (https://github.com/CiscoDevNet/ansible-nso/issues/1) +- nso_config now supports setting commit flags such as "no-networking", "commit-queue", etc. (https://github.com/CiscoDevNet/ansible-nso/issues/2) +- nso_config will now return a commit_results dictionary containing the results such as commit-queue-id, rollback-id, etc. (https://github.com/CiscoDevNet/ansible-nso/issues/3) + +v1.0.2 +====== + +Minor Changes +------------- + +- add GitHub Action to the repo for automated sanity and unit tests +- minor fixes to prepare for inclusion in Ansible 2.10 + +v1.0.1 +====== + +Minor Changes +------------- + +- Added See Also section to docs providing links to additional resources +- Added example for nso_action +- Corrected import paths in the test modules +- Defined data types for arguments in the docs where necessary to pass sanity tests +- Existing nso_config L3VPN example replaced with new examples due to existing example reliance on non-default l3vpn module +- Modified nso_verify module example +- Updated documentation with a See Also section providing links to NSO resources +- Updated examples for nso_show +- Updated examples in the documentation to align with the NSO DevNet Sandbox +- Verified all sanity and unit tests passing + +v1.0.0 +====== + +Release Summary +--------------- + +This is the first release of the ``cisco.nso`` collection. The modules in this collection were migrated from Ansible Core with no changes to their functionality. diff --git a/collections-debian-merged/ansible_collections/cisco/nso/FILES.json b/collections-debian-merged/ansible_collections/cisco/nso/FILES.json new file mode 100644 index 00000000..c7d60a17 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/FILES.json @@ -0,0 +1,523 @@ +{ + "files": [ + { + "name": ".", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "LICENSE", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "dce9a395bf65bac82e4e448b24ca4c13e86b8f9dff39a03049fe1e5f5b574c22", + "format": 1 + }, + { + "name": "plugins", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "plugins/doc_fragments", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "plugins/doc_fragments/nso.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "df22adca57a8c101f9255f537909838a8d84820cb36d7fff3d09ad9775f88946", + "format": 1 + }, + { + "name": "plugins/module_utils", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "plugins/module_utils/__init__.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "format": 1 + }, + { + "name": "plugins/module_utils/nso.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a25b074c7934dbbc0ea1a47b84f2937755f3ccd448c049f5ae0f77b6488ddf53", + "format": 1 + }, + { + "name": "plugins/modules", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "plugins/modules/nso_show.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "71072f473133f8261276135a652644872f6c416f38921531c5a65cf84c79c16e", + "format": 1 + }, + { + "name": "plugins/modules/nso_config.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "4df96d22a15b85deaad242b80a9aad4e80a289a6eeb22d7887a07904af484dee", + "format": 1 + }, + { + "name": "plugins/modules/__init__.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "format": 1 + }, + { + "name": "plugins/modules/nso_action.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ca08efa94eef66c5c1d5df1ffba39c83561b657618910c55be495d8432f1cda6", + "format": 1 + }, + { + "name": "plugins/modules/nso_query.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "7774ae70a38c74ec878fd0b284e2a715e76de3746033847c8a6faba2595f9371", + "format": 1 + }, + { + "name": "plugins/modules/nso_verify.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "1bdceaf7822a2bf604f8287cdfa4ade779229cd5159f56cebda093eab9cda563", + "format": 1 + }, + { + "name": "tests", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/unit", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/unit/compat", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/unit/compat/unittest.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "5401a046e5ce71fa19b6d905abd0f9bdf816c0c635f7bdda6730b3ef06e67096", + "format": 1 + }, + { + "name": "tests/unit/compat/builtins.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "0ca4cac919e166b25e601e11acb01f6957dddd574ff0a62569cb994a5ecb63e1", + "format": 1 + }, + { + "name": "tests/unit/compat/__init__.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "format": 1 + }, + { + "name": "tests/unit/compat/mock.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "0af958450cf6de3fbafe94b1111eae8ba5a8dbe1d785ffbb9df81f26e4946d99", + "format": 1 + }, + { + "name": "tests/unit/requirements.txt", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "bae23898d2424f99afdc207e2598c8cb827f78f86cd1880c5e92947a2750d988", + "format": 1 + }, + { + "name": "tests/unit/plugins", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/unit/plugins/module_utils", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/unit/plugins/module_utils/__init__.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "format": 1 + }, + { + "name": "tests/unit/plugins/module_utils/test_nso.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "383a733090b39ab8c0b7cc46f64ab6fe865018df305540f3992293835c0367b2", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/test_nso_verify.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e97c594a759aff1205fbfc87d109a4f37dec3aaa51503872de829ccf5a5635ca", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/test_nso_query.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "827dee13d856bde3c86eb3b3a9da75a205f3afed17b782c3ea219167c34322f6", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/__init__.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/test_nso_show.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "281c2c0e4bb08d87e5f521283dc379a6454513ae37b85e9dc483ff561f352927", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/utils.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "35890547afa3a972e402125de7907ea28abb33292c9d7779572d928ebc60c59f", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/test_nso_action.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "7e4e509ab2d752482f372b33ef7ed99206fd25a456e666e6343ef683188ae112", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/fixtures", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/fixtures/l3vpn_schema.json", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "5a0473c510e3d73aa1467c1d28198dbb8d2c48bccc558a1edecc76218f079079", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/fixtures/l3vpn_l3vpn_schema.json", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "dd1ae17c0b0682219f96d49f9b88ffba14e3f1a3f3928fe2518ce1197b9544ee", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/fixtures/device_schema.json", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "4ad85113c8433a2f2a9207ff7d2a134f3624447fb3fadc21c6b79eb793765b9a", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/fixtures/devices_schema.json", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "72539687ca9a0f968d824fe28d28416f787a890891df16318f6ae6cb2bd4b3ba", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/fixtures/verify_violation_data.json", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "8cefaf448b7fb40fb7a78a3174d280032c673fc5b1c5c6f729bd530f1b48d422", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/fixtures/description_schema.json", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "55ffec757d26f7baa8b57ce93dab987272980b8599b226ad93eee66f3412b450", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/fixtures/config_config.json", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "56bb3c57d697f91814f6a90fcbe2795d45f63613b3093f2cca8b9d787ebf83fa", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/fixtures/config_config_changes.json", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "5881dee7526fb9927f1b6def739e799c5ce4735a286e0b7ac11df2433589b24a", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/fixtures/l3vpn_l3vpn_endpoint_schema.json", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "f5464972c79daf6e0e22a89857d9f45004693edf82c2fa92cf2221a467ed09fe", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/fixtures/sync_from_schema.json", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "17a4b7aadbddb5ef37f62aa656ac8cfb7b5f978a2e8759a9f6cb6b67aba5872d", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/fixtures/complex_schema.json", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "4b8fe24cb6342fb46cfeea09926551e042e1a542a69c4650d18733eff081f901", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/fixtures/config_empty_data.json", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ca3d163bab055381827226140568f3bef7eaac187cebd76878e0b63e9e442356", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/nso_module.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "2920ea20515d52ce4a7fc91b23f588f58c24e0b08508113310f455da666aa6ba", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/test_nso_config.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b0a5b4b9d7e1aca690fc8519bfbbd96e4e9c0e940b815486fb62d50e2b2e8305", + "format": 1 + }, + { + "name": "tests/unit/mock", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/unit/mock/vault_helper.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "4535613601c419f7d20f0c21e638dabccf69b4a7fac99d5f6f9b81d1519dafd6", + "format": 1 + }, + { + "name": "tests/unit/mock/procenv.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a5af19933bcb8c65b14b15cdb4aff08716cca45858e0490a1b5b5d620657800e", + "format": 1 + }, + { + "name": "tests/unit/mock/__init__.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "format": 1 + }, + { + "name": "tests/unit/mock/loader.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "c45064a0beb765cd0b6cfbb74ca0cd491ceed2f4c2d22808f60a57071d9712cc", + "format": 1 + }, + { + "name": "tests/unit/mock/yaml_helper.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "88718a93edc6059b93ff526fb9b432cabf84628e0341a0469e82f288a6581c1f", + "format": 1 + }, + { + "name": "tests/unit/mock/path.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "4bb0e6a3ec2c478a7346a6881035639ebb34ff20773b38c3895035b9e4da8ece", + "format": 1 + }, + { + "name": "tests/unit/__init__.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "format": 1 + }, + { + "name": "tests/sanity", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "meta/runtime.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "48a2f61c72296aaa190a3ad670b0a5759bd047262b59b3d870e986b05878d87d", + "format": 1 + }, + { + "name": "changelogs", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "changelogs/fragments", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "changelogs/fragments/1.0.1.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a19a220214a31193a57e3195a2a75cfc1b56289cd0d5cada01e89ea3a8c04733", + "format": 1 + }, + { + "name": "changelogs/fragments/1.0.2.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "9983675bd9d59c7722e059693b87021eeb9d848b23d8e5db5ed1fbb49a130fb6", + "format": 1 + }, + { + "name": "changelogs/fragments/1.0.3.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "2ca03a5409fe673ee0674c828d6a59d9d921f9f4b331cdf943fb576b0f5f3822", + "format": 1 + }, + { + "name": "changelogs/config.yaml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "d411816c900e67b2fad4120350937246e6166abfc0a97515c178fdde1d5327ad", + "format": 1 + }, + { + "name": "changelogs/.plugin-cache.yaml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "7e194e3cf5ab6ccbbc29aad6ac51401fd361570bcde340d91fd6043a5d5468bb", + "format": 1 + }, + { + "name": "changelogs/changelog.yaml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "5f70979cc77d4ba707de93c6a8250f7ecf6e4e2d3b44d3bc4313784549ae616e", + "format": 1 + }, + { + "name": "README.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b74df289cf74ad96043f54179de6f6ba3a9a8462f22f2261ec75723c4a0671ef", + "format": 1 + }, + { + "name": ".gitignore", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "543c30cef64b6492ff37d3c4abf43d047f514290e73fc52f3997ac2b7aa5c303", + "format": 1 + }, + { + "name": ".github", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": ".github/workflows", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": ".github/workflows/ansible-test.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "822b4486d3f33c523fddac34e291889fc4f3d5dc279141dda8604055aadedfb4", + "format": 1 + }, + { + "name": "CHANGELOG.rst", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "293f3c6f10efb31e19e9950724834ed40aaccd0781c852ab08188303879cc07e", + "format": 1 + } + ], + "format": 1 +}
\ No newline at end of file diff --git a/collections-debian-merged/ansible_collections/cisco/nso/LICENSE b/collections-debian-merged/ansible_collections/cisco/nso/LICENSE new file mode 100644 index 00000000..4044ead0 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/LICENSE @@ -0,0 +1,678 @@ + +Copyright (c) 2019, Cisco Systems +All rights reserved. + + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + <program> Copyright (C) <year> <name of author> + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<http://www.gnu.org/licenses/>. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +<http://www.gnu.org/philosophy/why-not-lgpl.html>.
\ No newline at end of file diff --git a/collections-debian-merged/ansible_collections/cisco/nso/MANIFEST.json b/collections-debian-merged/ansible_collections/cisco/nso/MANIFEST.json new file mode 100644 index 00000000..3bf11c0c --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/MANIFEST.json @@ -0,0 +1,34 @@ +{ + "collection_info": { + "namespace": "cisco", + "name": "nso", + "version": "1.0.3", + "authors": [ + "Claes N\u00e4st\u00e9n (@cnasten)" + ], + "readme": "README.md", + "tags": [ + "cisco", + "nso", + "cloud", + "collection", + "networking" + ], + "description": "Ansible Modules for Cisco NSO", + "license": [], + "license_file": "LICENSE", + "dependencies": {}, + "repository": "https://github.com/CiscoDevNet/ansible-nso", + "documentation": "https://developer.cisco.com/docs/nso/", + "homepage": "https://github.com/CiscoDevNet/ansible-nso", + "issues": "https://github.com/CiscoDevNet/ansible-nso/issues" + }, + "file_manifest_file": { + "name": "FILES.json", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "f4077d527f0e02f81aef7fe7ef40648421ff5abd8208c4f9028597fa0e22af67", + "format": 1 + }, + "format": 1 +}
\ No newline at end of file diff --git a/collections-debian-merged/ansible_collections/cisco/nso/README.md b/collections-debian-merged/ansible_collections/cisco/nso/README.md new file mode 100644 index 00000000..ee1f27e4 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/README.md @@ -0,0 +1,83 @@ +# ansible-nso + +The ansible-nso project provides an Ansible collection for managing and automating your Cisco NSO environment. It consists of a set of modules and roles for performing tasks in NSO. + +This collection has been tested and supports version 5.3+ of NSO. + +*Note: This collection is not compatible with versions of Ansible before v2.9. + +## Requirements +Ansible v2.9 or newer + +## Install +Ansible must be installed +``` +sudo pip install ansible +``` + +Install the collection +``` +ansible-galaxy collection install cisco.nso +``` +## Use +Once the collection is installed, you can use it in a playbook by specifying the full namespace path to the module, plugin and/or role. + +```yaml +- hosts: nso + gather_facts: no + + tasks: + - name: CREATE DEVICE IN NSO + cisco.nso.nso_config: + url: https://10.10.20.49/jsonrpc + username: developer + password: C1sco12345 + data: + tailf-ncs:devices: + device: + - address: 10.10.20.175 + description: CONFIGURED BY ANSIBLE! + name: dist-rtr01 + authgroup: "labadmin" + device-type: + cli: + ned-id: "cisco-ios-cli-6.44" + port: "22" + state: + admin-state: "unlocked" +``` + +## Update +Getting the latest/nightly collection build + +### First Approach +Clone the ansible-nso repository. +``` +git clone https://github.com/CiscoDevNet/ansible-nso.git +``` + +Go to the ansible-nso directory +``` +cd ansible-nso +``` + +Pull the latest master on your NSO +``` +git pull origin master +``` + +Build and Install a collection from source +``` +ansible-galaxy collection build --force +ansible-galaxy collection install cisco-nso-* --force +``` + +### See Also: + +* [Ansible Using collections](https://docs.ansible.com/ansible/latest/user_guide/collections_using.html) for more details. + +## Contributing to this collection + +Ongoing development efforts and contributions to this collection are tracked as issues in this repository. + +We welcome community contributions to this collection. If you find problems, need an enhancement or need a new module, please open an issue or create a PR against the [Cisco NSO collection repository](https://github.com/CiscoDevNet/ansible-nso/issues).
\ No newline at end of file diff --git a/collections-debian-merged/ansible_collections/cisco/nso/changelogs/.plugin-cache.yaml b/collections-debian-merged/ansible_collections/cisco/nso/changelogs/.plugin-cache.yaml new file mode 100644 index 00000000..5958d025 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/changelogs/.plugin-cache.yaml @@ -0,0 +1,40 @@ +plugins: + become: {} + cache: {} + callback: {} + cliconf: {} + connection: {} + httpapi: {} + inventory: {} + lookup: {} + module: + nso_action: + description: Executes Cisco NSO actions and verifies output. + name: nso_action + namespace: '' + version_added: null + nso_config: + description: Manage Cisco NSO configuration and service synchronization. + name: nso_config + namespace: '' + version_added: null + nso_query: + description: Query data from Cisco NSO. + name: nso_query + namespace: '' + version_added: null + nso_show: + description: Displays data from Cisco NSO. + name: nso_show + namespace: '' + version_added: null + nso_verify: + description: Verifies Cisco NSO configuration. + name: nso_verify + namespace: '' + version_added: null + netconf: {} + shell: {} + strategy: {} + vars: {} +version: 1.0.3 diff --git a/collections-debian-merged/ansible_collections/cisco/nso/changelogs/changelog.yaml b/collections-debian-merged/ansible_collections/cisco/nso/changelogs/changelog.yaml new file mode 100644 index 00000000..d697e650 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/changelogs/changelog.yaml @@ -0,0 +1,47 @@ +ancestor: null +releases: + 1.0.0: + changes: + release_summary: This is the first release of the ``cisco.nso`` collection. + The modules in this collection were migrated from Ansible Core with no changes + to their functionality. + fragments: + - 1.0.0.yml + release_date: '2020-10-26' + 1.0.1: + changes: + minor_changes: + - Added See Also section to docs providing links to additional resources + - Added example for nso_action + - Corrected import paths in the test modules + - Defined data types for arguments in the docs where necessary to pass sanity + tests + - Existing nso_config L3VPN example replaced with new examples due to existing + example reliance on non-default l3vpn module + - Modified nso_verify module example + - Updated documentation with a See Also section providing links to NSO resources + - Updated examples for nso_show + - Updated examples in the documentation to align with the NSO DevNet Sandbox + - Verified all sanity and unit tests passing + fragments: + - 1.0.1.yml + release_date: '2020-10-30' + 1.0.2: + changes: + minor_changes: + - add GitHub Action to the repo for automated sanity and unit tests + - minor fixes to prepare for inclusion in Ansible 2.10 + fragments: + - 1.0.2.yml + release_date: '2020-12-02' + 1.0.3: + changes: + minor_changes: + - nso_action can now handle YANG model choices as input parameters (https://github.com/CiscoDevNet/ansible-nso/issues/1) + - nso_config now supports setting commit flags such as "no-networking", "commit-queue", + etc. (https://github.com/CiscoDevNet/ansible-nso/issues/2) + - nso_config will now return a commit_results dictionary containing the results + such as commit-queue-id, rollback-id, etc. (https://github.com/CiscoDevNet/ansible-nso/issues/3) + fragments: + - 1.0.3.yml + release_date: '2021-01-27' diff --git a/collections-debian-merged/ansible_collections/cisco/nso/changelogs/config.yaml b/collections-debian-merged/ansible_collections/cisco/nso/changelogs/config.yaml new file mode 100644 index 00000000..8a960c1f --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/changelogs/config.yaml @@ -0,0 +1,32 @@ +changelog_filename_template: ../CHANGELOG.rst +changelog_filename_version_depth: 0 +changes_file: changelog.yaml +changes_format: combined +ignore_other_fragment_extensions: true +keep_fragments: true +mention_ancestor: true +new_plugins_after_name: removed_features +notesdir: fragments +prelude_section_name: release_summary +prelude_section_title: Release Summary +sanitize_changelog: true +sections: +- - major_changes + - Major Changes +- - minor_changes + - Minor Changes +- - breaking_changes + - Breaking Changes / Porting Guide +- - deprecated_features + - Deprecated Features +- - removed_features + - Removed Features (previously deprecated) +- - security_fixes + - Security Fixes +- - bugfixes + - Bugfixes +- - known_issues + - Known Issues +title: Cisco NSO Ansible Collection +trivial_section_name: trivial +use_fqcn: true diff --git a/collections-debian-merged/ansible_collections/cisco/nso/changelogs/fragments/1.0.1.yml b/collections-debian-merged/ansible_collections/cisco/nso/changelogs/fragments/1.0.1.yml new file mode 100644 index 00000000..7b1bb95d --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/changelogs/fragments/1.0.1.yml @@ -0,0 +1,11 @@ +minor_changes: + - Updated examples in the documentation to align with the NSO DevNet Sandbox + - Added See Also section to docs providing links to additional resources + - Modified nso_verify module example + - Existing nso_config L3VPN example replaced with new examples due to existing example reliance on non-default l3vpn module + - Updated examples for nso_show + - Added example for nso_action + - Updated documentation with a See Also section providing links to NSO resources + - Corrected import paths in the test modules + - Defined data types for arguments in the docs where necessary to pass sanity tests + - Verified all sanity and unit tests passing
\ No newline at end of file diff --git a/collections-debian-merged/ansible_collections/cisco/nso/changelogs/fragments/1.0.2.yml b/collections-debian-merged/ansible_collections/cisco/nso/changelogs/fragments/1.0.2.yml new file mode 100644 index 00000000..f1b8ea9a --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/changelogs/fragments/1.0.2.yml @@ -0,0 +1,3 @@ +minor_changes: + - minor fixes to prepare for inclusion in Ansible 2.10 + - add GitHub Action to the repo for automated sanity and unit tests
\ No newline at end of file diff --git a/collections-debian-merged/ansible_collections/cisco/nso/changelogs/fragments/1.0.3.yml b/collections-debian-merged/ansible_collections/cisco/nso/changelogs/fragments/1.0.3.yml new file mode 100644 index 00000000..3865305b --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/changelogs/fragments/1.0.3.yml @@ -0,0 +1,5 @@ +minor_changes: + - nso_action can now handle YANG model choices as input parameters (https://github.com/CiscoDevNet/ansible-nso/issues/1) + - nso_config now supports setting commit flags such as "no-networking", "commit-queue", etc. (https://github.com/CiscoDevNet/ansible-nso/issues/2) + - nso_config will now return a commit_results dictionary containing the results such as commit-queue-id, rollback-id, etc. (https://github.com/CiscoDevNet/ansible-nso/issues/3) +
\ No newline at end of file diff --git a/collections-debian-merged/ansible_collections/cisco/nso/meta/runtime.yml b/collections-debian-merged/ansible_collections/cisco/nso/meta/runtime.yml new file mode 100644 index 00000000..1f18fd72 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/meta/runtime.yml @@ -0,0 +1,2 @@ +--- +requires_ansible: '>=2.9.10'
\ No newline at end of file diff --git a/collections-debian-merged/ansible_collections/cisco/nso/plugins/doc_fragments/nso.py b/collections-debian-merged/ansible_collections/cisco/nso/plugins/doc_fragments/nso.py new file mode 100644 index 00000000..11d458db --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/plugins/doc_fragments/nso.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- + +# Copyright: (c) 2017, Cisco and/or its affiliates. +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +class ModuleDocFragment(object): + + DOCUMENTATION = r''' +options: + url: + description: NSO JSON-RPC URL, http://localhost:8080/jsonrpc + type: str + required: true + username: + description: NSO username + type: str + required: true + password: + description: NSO password + type: str + required: true + timeout: + description: JSON-RPC request timeout in seconds + type: int + default: 300 + validate_certs: + description: When set to true, validates the SSL certificate of NSO when + using SSL + type: bool + required: false + default: false +seealso: + - name: Cisco DevNet NSO Sandbox + description: Provides a reservable pod with NSO, virtual network topology simulated with Cisco CML and a Linux host running Ansible + link: https://blogs.cisco.com/developer/nso-learning-lab-and-sandbox + - name: NSO Developer Resources on DevNet + description: Documentation for getting started using NSO + link: https://developer.cisco.com/docs/nso/ + - name: NSO Developer Hub + description: Collaboration community portal for NSO developers + link: https://community.cisco.com/t5/nso-developer-hub/ct-p/5672j-dev-nso + - name: NSO Developer Github + description: Code for NSO on Github + link: https://github.com/NSO-developer/ +''' diff --git a/collections-debian-merged/ansible_collections/cisco/nso/plugins/module_utils/__init__.py b/collections-debian-merged/ansible_collections/cisco/nso/plugins/module_utils/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/plugins/module_utils/__init__.py diff --git a/collections-debian-merged/ansible_collections/cisco/nso/plugins/module_utils/nso.py b/collections-debian-merged/ansible_collections/cisco/nso/plugins/module_utils/nso.py new file mode 100644 index 00000000..5e469cdd --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/plugins/module_utils/nso.py @@ -0,0 +1,833 @@ +# -*- coding: utf-8 -*- + +# Copyright: (c) 2017, Cisco and/or its affiliates. +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +from ansible.module_utils.basic import env_fallback +from ansible.module_utils.urls import open_url +from ansible.module_utils._text import to_text + +import json +import re +import socket + +try: + unicode + HAVE_UNICODE = True +except NameError: + unicode = str + HAVE_UNICODE = False + + +nso_argument_spec = dict( + url=dict(type='str', required=True), + username=dict(type='str', required=True, fallback=(env_fallback, ['ANSIBLE_NET_USERNAME'])), + password=dict(type='str', required=True, no_log=True, fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD'])), + timeout=dict(type='int', default=300), + validate_certs=dict(type='bool', default=False) +) + + +class State(object): + SET = 'set' + PRESENT = 'present' + ABSENT = 'absent' + CHECK_SYNC = 'check-sync' + DEEP_CHECK_SYNC = 'deep-check-sync' + IN_SYNC = 'in-sync' + DEEP_IN_SYNC = 'deep-in-sync' + + SYNC_STATES = ('check-sync', 'deep-check-sync', 'in-sync', 'deep-in-sync') + + +class ModuleFailException(Exception): + def __init__(self, message): + super(ModuleFailException, self).__init__(message) + self.message = message + + +class NsoException(Exception): + def __init__(self, message, error): + super(NsoException, self).__init__(message) + self.message = message + self.error = error + + +class JsonRpc(object): + def __init__(self, url, timeout, validate_certs): + self._url = url + self._timeout = timeout + self._validate_certs = validate_certs + self._id = 0 + self._trans = {} + self._headers = {'Content-Type': 'application/json'} + self._conn = None + self._system_settings = {} + + def login(self, user, passwd): + payload = { + 'method': 'login', + 'params': {'user': user, 'passwd': passwd} + } + resp, resp_json = self._call(payload) + self._headers['Cookie'] = resp.headers['set-cookie'] + + def logout(self): + payload = {'method': 'logout', 'params': {}} + self._call(payload) + + def get_system_setting(self, setting): + if setting not in self._system_settings: + payload = {'method': 'get_system_setting', 'params': {'operation': setting}} + resp, resp_json = self._call(payload) + self._system_settings[setting] = resp_json['result'] + return self._system_settings[setting] + + def new_trans(self, **kwargs): + payload = {'method': 'new_trans', 'params': kwargs} + resp, resp_json = self._call(payload) + return resp_json['result']['th'] + + def get_trans(self, mode): + if mode not in self._trans: + th = self.new_trans(mode=mode) + self._trans[mode] = th + return self._trans[mode] + + def delete_trans(self, th): + payload = {'method': 'delete_trans', 'params': {'th': th}} + resp, resp_json = self._call(payload) + self._maybe_delete_trans(th) + + def validate_trans(self, th): + payload = {'method': 'validate_trans', 'params': {'th': th}} + resp, resp_json = self._write_call(payload) + return resp_json['result'] + + def get_trans_changes(self, th): + payload = {'method': 'get_trans_changes', 'params': {'th': th}} + resp, resp_json = self._write_call(payload) + return resp_json['result']['changes'] + + def validate_commit(self, th, flags=None): + if flags: + payload = {'method': 'validate_commit', 'params': {'th': th, 'flags': flags}} + else: + payload = {'method': 'validate_commit', 'params': {'th': th}} + resp, resp_json = self._write_call(payload) + return resp_json['result'].get('warnings', []) + + def commit(self, th, flags=None): + if flags: + payload = {'method': 'commit', 'params': {'th': th, 'flags': flags}} + else: + payload = {'method': 'commit', 'params': {'th': th}} + resp, resp_json = self._write_call(payload) + if len(resp_json['result']) == 0: + self._maybe_delete_trans(th) + return resp_json['result'] + + def get_schema(self, **kwargs): + payload = {'method': 'get_schema', 'params': kwargs} + resp, resp_json = self._maybe_write_call(payload) + return resp_json['result'] + + def get_module_prefix_map(self, path=None): + if path is None: + payload = {'method': 'get_module_prefix_map', 'params': {}} + resp, resp_json = self._call(payload) + else: + payload = {'method': 'get_module_prefix_map', 'params': {'path': path}} + resp, resp_json = self._maybe_write_call(payload) + return resp_json['result'] + + def get_value(self, path): + payload = { + 'method': 'get_value', + 'params': {'path': path} + } + resp, resp_json = self._read_call(payload) + return resp_json['result'] + + def exists(self, path): + payload = {'method': 'exists', 'params': {'path': path}} + try: + resp, resp_json = self._read_call(payload) + return resp_json['result']['exists'] + except NsoException as ex: + # calling exists on a sub-list when the parent list does + # not exists will cause data.not_found errors on recent + # NSO + if 'type' in ex.error and ex.error['type'] == 'data.not_found': + return False + raise + + def create(self, th, path): + payload = {'method': 'create', 'params': {'th': th, 'path': path}} + self._write_call(payload) + + def delete(self, th, path): + payload = {'method': 'delete', 'params': {'th': th, 'path': path}} + self._write_call(payload) + + def set_value(self, th, path, value): + payload = { + 'method': 'set_value', + 'params': {'th': th, 'path': path, 'value': value} + } + resp, resp_json = self._write_call(payload) + return resp_json['result'] + + def show_config(self, path, operational=False): + payload = { + 'method': 'show_config', + 'params': { + 'path': path, + 'result_as': 'json', + 'with_oper': operational} + } + resp, resp_json = self._read_call(payload) + return resp_json['result'] + + def query(self, xpath, fields): + payload = { + 'method': 'query', + 'params': { + 'xpath_expr': xpath, + 'selection': fields + } + } + resp, resp_json = self._read_call(payload) + return resp_json['result']['results'] + + def run_action(self, th, path, params=None): + if params is None: + params = {} + + if is_version(self, [(4, 5), (4, 4, 3)]): + result_format = 'json' + else: + result_format = 'normal' + + payload = { + 'method': 'run_action', + 'params': { + 'format': result_format, + 'path': path, + 'params': params + } + } + + if th is None: + resp, resp_json = self._read_call(payload) + else: + payload['params']['th'] = th + resp, resp_json = self._call(payload) + + if result_format == 'normal': + # this only works for one-level results, list entries, + # containers etc will have / in their name. + result = {} + for info in resp_json['result']: + result[info['name']] = info['value'] + else: + result = resp_json['result'] + + return result + + def _call(self, payload): + self._id += 1 + if 'id' not in payload: + payload['id'] = self._id + + if 'jsonrpc' not in payload: + payload['jsonrpc'] = '2.0' + + data = json.dumps(payload) + try: + resp = open_url( + self._url, timeout=self._timeout, + method='POST', data=data, headers=self._headers, + validate_certs=self._validate_certs) + if resp.code != 200: + raise NsoException( + 'NSO returned HTTP code {0}, expected 200'.format(resp.status), {}) + except socket.timeout: + raise NsoException('request timed out against NSO at {0}'.format(self._url), {}) + + resp_body = resp.read() + resp_json = json.loads(resp_body) + + if 'error' in resp_json: + self._handle_call_error(payload, resp_json) + return resp, resp_json + + def _handle_call_error(self, payload, resp_json): + method = payload['method'] + + error = resp_json['error'] + error_type = error['type'][len('rpc.method.'):] + if error_type in ('unexpected_params', + 'unknown_params_value', + 'invalid_params', + 'invalid_params_type', + 'data_not_found'): + key = error['data']['param'] + error_type_s = error_type.replace('_', ' ') + if key == 'path': + msg = 'NSO {0} {1}. path = {2}'.format( + method, error_type_s, payload['params']['path']) + else: + path = payload['params'].get('path', 'unknown') + msg = 'NSO {0} {1}. path = {2}. {3} = {4}'.format( + method, error_type_s, path, key, payload['params'][key]) + else: + msg = 'NSO {0} returned JSON-RPC error: {1}'.format(method, error) + + raise NsoException(msg, error) + + def _read_call(self, payload): + if 'th' not in payload['params']: + payload['params']['th'] = self.get_trans(mode='read') + return self._call(payload) + + def _write_call(self, payload): + if 'th' not in payload['params']: + payload['params']['th'] = self.get_trans(mode='read_write') + return self._call(payload) + + def _maybe_write_call(self, payload): + if 'read_write' in self._trans: + return self._write_call(payload) + else: + return self._read_call(payload) + + def _maybe_delete_trans(self, th): + for mode in ('read', 'read_write'): + if th == self._trans.get(mode, None): + del self._trans[mode] + + +class ValueBuilder(object): + PATH_RE = re.compile('{[^}]*}') + PATH_RE_50 = re.compile('{[^}]*}$') + + class Value(object): + __slots__ = ['path', 'tag_path', 'state', 'value', 'deps'] + + def __init__(self, path, state, value, deps): + self.path = path + self.tag_path = ValueBuilder.PATH_RE.sub('', path) + self.state = state + self.value = value + self.deps = deps + + # nodes can depend on themselves + if self.tag_path in self.deps: + self.deps.remove(self.tag_path) + + def __lt__(self, rhs): + l_len = len(self.path.split('/')) + r_len = len(rhs.path.split('/')) + if l_len == r_len: + return self.path.__lt__(rhs.path) + return l_len < r_len + + def __str__(self): + return 'Value<path={0}, state={1}, value={2}>'.format( + self.path, self.state, self.value) + + class ValueIterator(object): + def __init__(self, client, values, delayed_values): + self._client = client + self._values = values + self._delayed_values = delayed_values + self._pos = 0 + + def __iter__(self): + return self + + def __next__(self): + return self.next() + + def next(self): + if self._pos >= len(self._values): + if len(self._delayed_values) == 0: + raise StopIteration() + + builder = ValueBuilder(self._client, delay=False) + for (parent, maybe_qname, value) in self._delayed_values: + builder.build(parent, maybe_qname, value) + del self._delayed_values[:] + self._values.extend(builder.values) + + return self.next() + + value = self._values[self._pos] + self._pos += 1 + return value + + def __init__(self, client, mode='config', delay=None): + self._client = client + self._mode = mode + self._schema_cache = {} + self._module_prefix_map_cache = {} + self._values = [] + self._values_dirty = False + self._delay = delay is None and mode == 'config' and is_version(self._client, [(5, 0)]) + self._delayed_values = [] + + def build(self, parent, maybe_qname, value, schema=None): + qname, name = self.get_prefix_name(parent, maybe_qname) + if name is None: + path = parent + else: + path = '{0}/{1}'.format(parent, qname) + + if schema is None: + schema = self._get_schema(path) + + if self._delay and schema.get('is_mount_point', False): + # delay conversion of mounted values, required to get + # shema information on 5.0 and later. + self._delayed_values.append((parent, maybe_qname, value)) + elif self._is_leaf_list(schema) and is_version(self._client, [(4, 5)]): + self._build_leaf_list(path, schema, value) + elif self._is_leaf(schema): + deps = schema.get('deps', []) + if self._is_empty_leaf(schema): + exists = self._client.exists(path) + if exists and value != [None]: + self._add_value(path, State.ABSENT, None, deps) + elif not exists and value == [None]: + self._add_value(path, State.PRESENT, None, deps) + else: + if maybe_qname is None: + value_type = self.get_type(path) + else: + value_type = self._get_child_type(parent, qname) + + if 'identityref' in value_type: + if isinstance(value, list): + value = [ll_v for ll_v, t_ll_v + in [self.get_prefix_name(parent, v) for v in value]] + else: + value, t_value = self.get_prefix_name(parent, value) + self._add_value(path, State.SET, value, deps) + elif isinstance(value, dict): + self._build_dict(path, schema, value) + elif isinstance(value, list): + self._build_list(path, schema, value) + else: + raise ModuleFailException( + 'unsupported schema {0} at {1}'.format( + schema['kind'], path)) + + @property + def values(self): + if self._values_dirty: + self._values = ValueBuilder.sort_values(self._values) + self._values_dirty = False + + return ValueBuilder.ValueIterator(self._client, self._values, self._delayed_values) + + @staticmethod + def sort_values(values): + class N(object): + def __init__(self, v): + self.tmp_mark = False + self.mark = False + self.v = v + + sorted_values = [] + nodes = [N(v) for v in sorted(values)] + + def get_node(tag_path): + return next((m for m in nodes + if m.v.tag_path == tag_path), None) + + def is_cycle(n, dep, visited): + visited.add(n.v.tag_path) + if dep in visited: + return True + + dep_n = get_node(dep) + if dep_n is not None: + for sub_dep in dep_n.v.deps: + if is_cycle(dep_n, sub_dep, visited): + return True + + return False + + # check for dependency cycles, remove if detected. sort will + # not be 100% but allows for a best-effort to work around + # issue in NSO. + for n in nodes: + for dep in n.v.deps: + if is_cycle(n, dep, set()): + n.v.deps.remove(dep) + + def visit(n): + if n.tmp_mark: + return False + if not n.mark: + n.tmp_mark = True + for m in nodes: + if m.v.tag_path in n.v.deps: + if not visit(m): + return False + + n.tmp_mark = False + n.mark = True + + sorted_values.insert(0, n.v) + + return True + + n = next((n for n in nodes if not n.mark), None) + while n is not None: + visit(n) + n = next((n for n in nodes if not n.mark), None) + + return sorted_values[::-1] + + def _build_dict(self, path, schema, value): + keys = schema.get('key', []) + for dict_key, dict_value in value.items(): + qname, name = self.get_prefix_name(path, dict_key) + if dict_key in ('__state', ) or name in keys: + continue + + child_schema = self._find_child(path, schema, qname) + self.build(path, dict_key, dict_value, child_schema) + + def _build_leaf_list(self, path, schema, value): + deps = schema.get('deps', []) + entry_type = self.get_type(path, schema) + + if self._mode == 'verify': + for entry in value: + if 'identityref' in entry_type: + entry, t_entry = self.get_prefix_name(path, entry) + entry_path = '{0}{{{1}}}'.format(path, entry) + if not self._client.exists(entry_path): + self._add_value(entry_path, State.ABSENT, None, deps) + else: + # remove leaf list if treated as a list and then re-create the + # expected list entries. + self._add_value(path, State.ABSENT, None, deps) + + for entry in value: + if 'identityref' in entry_type: + entry, t_entry = self.get_prefix_name(path, entry) + entry_path = '{0}{{{1}}}'.format(path, entry) + self._add_value(entry_path, State.PRESENT, None, deps) + + def _build_list(self, path, schema, value): + deps = schema.get('deps', []) + for entry in value: + entry_key = self._build_key(path, entry, schema['key']) + entry_path = '{0}{{{1}}}'.format(path, entry_key) + entry_state = entry.get('__state', 'present') + entry_exists = self._client.exists(entry_path) + + if entry_state == 'absent': + if entry_exists: + self._add_value(entry_path, State.ABSENT, None, deps) + else: + if not entry_exists: + self._add_value(entry_path, State.PRESENT, None, deps) + if entry_state in State.SYNC_STATES: + self._add_value(entry_path, entry_state, None, deps) + + self.build(entry_path, None, entry) + + def _build_key(self, path, entry, schema_keys): + key_parts = [] + for key in schema_keys: + value = entry.get(key, None) + if value is None: + raise ModuleFailException( + 'required leaf {0} in {1} not set in data'.format( + key, path)) + + value_type = self._get_child_type(path, key) + if 'identityref' in value_type: + value, t_value = self.get_prefix_name(path, value) + key_parts.append(self._quote_key(value)) + return ' '.join(key_parts) + + def _quote_key(self, key): + if isinstance(key, bool): + return key and 'true' or 'false' + + q_key = [] + for c in str(key): + if c in ('{', '}', "'", '\\'): + q_key.append('\\') + q_key.append(c) + q_key = ''.join(q_key) + if ' ' in q_key: + return '"{0}"'.format(q_key) + return q_key + + def _find_child(self, path, schema, qname): + if 'children' not in schema: + schema = self._get_schema(path) + + # look for the qualified name if : is in the name + child_schema = self._get_child(schema, qname) + if child_schema is not None: + return child_schema + + # no child was found, look for a choice with a child matching + for child_schema in schema['children']: + if child_schema['kind'] != 'choice': + continue + choice_child_schema = self._get_choice_child(child_schema, qname) + if choice_child_schema is not None: + return choice_child_schema + + raise ModuleFailException( + 'no child in {0} with name {1}. children {2}'.format( + path, qname, ','.join((c.get('qname', c.get('name', None)) for c in schema['children'])))) + + def _add_value(self, path, state, value, deps): + self._values.append(ValueBuilder.Value(path, state, value, deps)) + self._values_dirty = True + + def get_prefix_name(self, path, qname): + if not isinstance(qname, (str, unicode)): + return qname, None + if ':' not in qname: + return qname, qname + + module_prefix_map = self._get_module_prefix_map(path) + module, name = qname.split(':', 1) + if module not in module_prefix_map: + raise ModuleFailException( + 'no module mapping for module {0}. loaded modules {1}'.format( + module, ','.join(sorted(module_prefix_map.keys())))) + + return '{0}:{1}'.format(module_prefix_map[module], name), name + + def _get_schema(self, path): + return self._ensure_schema_cached(path)['data'] + + def _get_child_type(self, parent_path, key): + all_schema = self._ensure_schema_cached(parent_path) + parent_schema = all_schema['data'] + meta = all_schema['meta'] + schema = self._find_child(parent_path, parent_schema, key) + return self.get_type(parent_path, schema, meta) + + def get_type(self, path, schema=None, meta=None): + if schema is None or meta is None: + all_schema = self._ensure_schema_cached(path) + schema = all_schema['data'] + meta = all_schema['meta'] + + if self._is_leaf(schema): + def get_type(meta, curr_type): + if curr_type.get('primitive', False): + return [curr_type['name']] + if 'namespace' in curr_type: + curr_type_key = '{0}:{1}'.format( + curr_type['namespace'], curr_type['name']) + type_info = meta['types'][curr_type_key][-1] + return get_type(meta, type_info) + if 'leaf_type' in curr_type: + return get_type(meta, curr_type['leaf_type'][-1]) + if 'union' in curr_type: + union_types = [] + for union_type in curr_type['union']: + union_types.extend(get_type(meta, union_type[-1])) + return union_types + return [curr_type.get('name', 'unknown')] + + return get_type(meta, schema['type']) + return None + + def _ensure_schema_cached(self, path): + if not self._delay and is_version(self._client, [(5, 0)]): + # newer versions of NSO support multiple different schemas + # for different devices, thus the device is required to + # look up the schema. Remove the key entry to get schema + # logic working ok. + path = ValueBuilder.PATH_RE_50.sub('', path) + else: + path = ValueBuilder.PATH_RE.sub('', path) + + if path not in self._schema_cache: + schema = self._client.get_schema(path=path, levels=1) + self._schema_cache[path] = schema + return self._schema_cache[path] + + def _get_module_prefix_map(self, path): + # newer versions of NSO support multiple mappings from module + # to prefix depending on which device is used. + if path != '' and is_version(self._client, [(5, 0)]): + if path not in self._module_prefix_map_cache: + self._module_prefix_map_cache[path] = self._client.get_module_prefix_map(path) + return self._module_prefix_map_cache[path] + + if '' not in self._module_prefix_map_cache: + self._module_prefix_map_cache[''] = self._client.get_module_prefix_map() + return self._module_prefix_map_cache[''] + + def _get_child(self, schema, qname): + # no child specified, return parent + if qname is None: + return schema + + name_key = ':' in qname and 'qname' or 'name' + return next((c for c in schema['children'] + if c.get(name_key, None) == qname), None) + + def _get_choice_child(self, schema, qname): + name_key = ':' in qname and 'qname' or 'name' + for child_case in schema['cases']: + # look for direct child + choice_child_schema = next( + (c for c in child_case['children'] + if c.get(name_key, None) == qname), None) + if choice_child_schema is not None: + return choice_child_schema + + # look for nested choice + for child_schema in child_case['children']: + if child_schema['kind'] != 'choice': + continue + choice_child_schema = self._get_choice_child(child_schema, qname) + if choice_child_schema is not None: + return choice_child_schema + return None + + def _is_leaf_list(self, schema): + return schema.get('kind', None) == 'leaf-list' + + def _is_leaf(self, schema): + # still checking for leaf-list here to be compatible with pre + # 4.5 versions of NSO. + return schema.get('kind', None) in ('key', 'leaf', 'leaf-list') + + def _is_empty_leaf(self, schema): + return (schema.get('kind', None) == 'leaf' and + schema['type'].get('primitive', False) and + schema['type'].get('name', '') == 'empty') + + +def connect(params): + client = JsonRpc(params['url'], + params['timeout'], + params['validate_certs']) + client.login(params['username'], params['password']) + return client + + +def verify_version(client, required_versions): + version_str = client.get_system_setting('version') + client._version = version_str + if not verify_version_str(version_str, required_versions): + supported_versions = ', '.join( + ['.'.join([str(p) for p in required_version]) + for required_version in required_versions]) + raise ModuleFailException( + 'unsupported NSO version {0}. {1} or later supported'.format( + version_str, supported_versions)) + + +def is_version(client, required_versions): + version_str = client.get_system_setting('version') + return verify_version_str(version_str, required_versions) + + +def verify_version_str(version_str, required_versions): + version_str = re.sub('_.*', '', version_str) + + version = [int(p) for p in version_str.split('.')] + if len(version) < 2: + raise ModuleFailException( + 'unsupported NSO version format {0}'.format(version_str)) + + def check_version(required_version, version): + for pos in range(len(required_version)): + if pos >= len(version): + return False + if version[pos] > required_version[pos]: + return True + if version[pos] < required_version[pos]: + return False + return True + + for required_version in required_versions: + if check_version(required_version, version): + return True + return False + + +def normalize_value(expected_value, value, key): + if value is None: + return None + if (isinstance(expected_value, bool) and + isinstance(value, (str, unicode))): + return value == 'true' + if isinstance(expected_value, int): + try: + return int(value) + except TypeError: + raise ModuleFailException( + 'returned value {0} for {1} is not a valid integer'.format( + key, value)) + if isinstance(expected_value, float): + try: + return float(value) + except TypeError: + raise ModuleFailException( + 'returned value {0} for {1} is not a valid float'.format( + key, value)) + if isinstance(expected_value, (list, tuple)): + if not isinstance(value, (list, tuple)): + raise ModuleFailException( + 'returned value {0} for {1} is not a list'.format(value, key)) + if len(expected_value) != len(value): + raise ModuleFailException( + 'list length mismatch for {0}'.format(key)) + + normalized_value = [] + for i in range(len(expected_value)): + normalized_value.append( + normalize_value(expected_value[i], value[i], '{0}[{1}]'.format(key, i))) + return normalized_value + + if isinstance(expected_value, dict): + if not isinstance(value, dict): + raise ModuleFailException( + 'returned value {0} for {1} is not a dict'.format(value, key)) + if len(expected_value) != len(value): + raise ModuleFailException( + 'dict length mismatch for {0}'.format(key)) + + normalized_value = {} + for k in expected_value.keys(): + n_k = normalize_value(k, k, '{0}[{1}]'.format(key, k)) + if n_k not in value: + raise ModuleFailException('missing {0} in value'.format(n_k)) + normalized_value[n_k] = normalize_value(expected_value[k], value[k], '{0}[{1}]'.format(key, k)) + return normalized_value + + if HAVE_UNICODE: + if isinstance(expected_value, unicode) and isinstance(value, str): + return value.decode('utf-8') + if isinstance(expected_value, str) and isinstance(value, unicode): + return value.encode('utf-8') + else: + if hasattr(expected_value, 'encode') and hasattr(value, 'decode'): + return value.decode('utf-8') + if hasattr(expected_value, 'decode') and hasattr(value, 'encode'): + return value.encode('utf-8') + + return value diff --git a/collections-debian-merged/ansible_collections/cisco/nso/plugins/modules/__init__.py b/collections-debian-merged/ansible_collections/cisco/nso/plugins/modules/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/plugins/modules/__init__.py diff --git a/collections-debian-merged/ansible_collections/cisco/nso/plugins/modules/nso_action.py b/collections-debian-merged/ansible_collections/cisco/nso/plugins/modules/nso_action.py new file mode 100644 index 00000000..b5db2084 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/plugins/modules/nso_action.py @@ -0,0 +1,211 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright (c) 2017 Cisco and/or its affiliates. +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. +# + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +DOCUMENTATION = ''' +--- +module: nso_action +extends_documentation_fragment: +- cisco.nso.nso + +short_description: Executes Cisco NSO actions and verifies output. +description: + - This module provides support for executing Cisco NSO actions and then + verifying that the output is as expected. +requirements: + - Cisco NSO version 3.4 or higher. +author: "Claes Nästén (@cnasten)" +options: + path: + description: Path to NSO action. + required: true + type: str + input: + description: > + NSO action parameters. + type: dict + output_required: + description: > + Required output parameters. + type: dict + output_invalid: + description: > + List of result parameter names that will cause the task to fail if they + are present. + type: dict + validate_strict: + description: > + If set to true, the task will fail if any output parameters not in + output_required is present in the output. + type: bool + default: False +''' + +EXAMPLES = ''' +- name: Sync NSO device + cisco.nso.nso_action: + url: https://10.10.20.49/jsonrpc + username: developer + password: C1sco12345 + path: /ncs:devices/device{dist-rtr01}/sync-from + input: {} + +- name: Check device sync + cisco.nso.nso_action: + url: https://10.10.20.49/jsonrpc + username: developer + password: C1sco12345 + path: /ncs:devices/check-sync + input: {} + +- name: Load Native Config + cisco.nso.nso_action: + url: "https://10.10.20.49/jsonrpc" + username: developer + password: C1sco12345 + path: /ncs:devices/ncs:device{dist-rtr01}/load-native-config + input: { file: "/home/developer/test.cfg" , verbose: true, mode: "merge"} + register: result +''' + +RETURN = ''' +output: + description: Action output + returned: success + type: dict + sample: + result: true +''' + +from ansible_collections.cisco.nso.plugins.module_utils.nso import connect, verify_version, nso_argument_spec +from ansible_collections.cisco.nso.plugins.module_utils.nso import normalize_value +from ansible_collections.cisco.nso.plugins.module_utils.nso import ModuleFailException, NsoException +from ansible.module_utils.basic import AnsibleModule + + +class NsoAction(object): + + REQUIRED_VERSIONS = [ + (3, 4) + ] + + def __init__(self, check_mode, client, + path, input, + output_required, output_invalid, validate_strict): + self._check_mode = check_mode + self._client = client + self._path = path + self._input = input + self._output_required = output_required + self._output_invalid = output_invalid + self._validate_strict = validate_strict + + def main(self): + schema = self._client.get_schema(path=self._path) + if schema['data']['kind'] != 'action': + raise ModuleFailException('{0} is not an action'.format(self._path)) + input_schema = [] + for c in schema['data']['children']: + if c.get('is_action_input', False): + if c['kind'] == 'choice': + for case in c['cases']: + input_schema.append(case) + else: + input_schema.append(c) + + for key, value in self._input.items(): + child = next((c for c in input_schema if c['name'] == key), None) + if child is None: + raise ModuleFailException("unsupported input parameter '{0}'".format(key)) + + # implement type validation in the future + + if self._check_mode: + return {} + else: + return self._run_and_verify() + + def _run_and_verify(self): + output = self._client.run_action(None, self._path, self._input) + for key, value in self._output_required.items(): + if key not in output: + raise ModuleFailException('{0} not in result'.format(key)) + + n_value = normalize_value(value, output[key], key) + if value != n_value: + msg = '{0} value mismatch. expected {1} got {2}'.format( + key, value, n_value) + raise ModuleFailException(msg) + + for key in self._output_invalid.keys(): + if key in output: + raise ModuleFailException('{0} not allowed in result'.format(key)) + + if self._validate_strict: + for name in output.keys(): + if name not in self._output_required: + raise ModuleFailException('{0} not allowed in result'.format(name)) + + return output + + +def main(): + argument_spec = dict( + path=dict(required=True), + input=dict(required=False, type='dict', default={}), + output_required=dict(required=False, type='dict', default={}), + output_invalid=dict(required=False, type='dict', default={}), + validate_strict=dict(required=False, type='bool', default=False) + ) + argument_spec.update(nso_argument_spec) + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True + ) + p = module.params + + client = connect(p) + nso_action = NsoAction( + module.check_mode, client, + p['path'], + p['input'], + p['output_required'], + p['output_invalid'], + p['validate_strict']) + try: + verify_version(client, NsoAction.REQUIRED_VERSIONS) + + output = nso_action.main() + client.logout() + module.exit_json(changed=True, output=output) + except NsoException as ex: + client.logout() + module.fail_json(msg=ex.message) + except ModuleFailException as ex: + client.logout() + module.fail_json(msg=ex.message) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/cisco/nso/plugins/modules/nso_config.py b/collections-debian-merged/ansible_collections/cisco/nso/plugins/modules/nso_config.py new file mode 100644 index 00000000..01ee40ec --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/plugins/modules/nso_config.py @@ -0,0 +1,338 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright (c) 2017 Cisco and/or its affiliates. +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. +# + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +DOCUMENTATION = ''' +--- +module: nso_config +extends_documentation_fragment: +- cisco.nso.nso + +short_description: Manage Cisco NSO configuration and service synchronization. +description: + - This module provides support for managing configuration in Cisco NSO and + can also ensure services are in sync. +requirements: + - Cisco NSO version 3.4.12 or higher, 4.2.7 or higher, + 4.3.8 or higher, 4.4.3 or higher, 4.5 or higher. +author: "Claes Nästén (@cnasten)" +options: + data: + description: > + NSO data in format as | display json converted to YAML. List entries can + be annotated with a __state entry. Set to in-sync/deep-in-sync for + services to verify service is in sync with the network. Set to absent in + list entries to ensure they are deleted if they exist in NSO. + required: true + type: dict + commit_flags: + description: > + A list containing commit flags. See the API documentation for + supported commit flags. + https://developer.cisco.com/docs/nso/guides/#!life-cycle-operations-how-to-manipulate-existing-services-and-devices/commit-flags-and-device-service-actions + type: list + elements: str +''' + +EXAMPLES = ''' +- name: CREATE DEVICE IN NSO + cisco.nso.nso_config: + url: https://10.10.20.49/jsonrpc + username: developer + password: C1sco12345 + data: + tailf-ncs:devices: + device: + - address: 10.10.20.175 + description: CONFIGURED BY ANSIBLE! + name: dist-rtr01 + authgroup: "labadmin" + device-type: + cli: + ned-id: "cisco-ios-cli-6.44" + port: "22" + state: + admin-state: "unlocked" + +- name: ADD NEW LOOPBACK + cisco.nso.nso_config: + url: https://10.10.20.49/jsonrpc + username: developer + password: C1sco12345 + data: + tailf-ncs:devices: + device: + - name: dist-rtr01 + config: + tailf-ned-cisco-ios:interface: + Loopback: + - name: "1" + description: Created by Ansible! + +- name: CONFIGURE IP ADDRESS ON LOOPBACK + cisco.nso.nso_config: + url: https://10.10.20.49/jsonrpc + username: developer + password: C1sco12345 + data: + tailf-ncs:devices: + device: + - name: dist-rtr01 + config: + tailf-ned-cisco-ios:interface: + Loopback: + - name: "1" + description: Created by Ansible! + ip: + address: + primary: + address: 10.10.10.10 + mask: 255.255.255.255 + +- name: CONFIGURE NTP SERVER ON DEVICE + cisco.nso.nso_config: + url: https://10.10.20.49/jsonrpc + username: developer + password: C1sco12345 + data: + tailf-ncs:devices: + device: + - name: dist-rtr01 + config: + tailf-ned-cisco-ios:ntp: + server: + peer-list: + - name: 2.2.2.2 +''' + +RETURN = ''' +changes: + description: List of changes + returned: always + type: complex + sample: + - path: "/ncs:devices/device{dist-rtr01}/config/ios:interface/Loopback{1}/ip/address/primary/address" + from: null + to: "10.10.10.10" + type: set + contains: + path: + description: Path to value changed + returned: always + type: str + from: + description: Previous value if any, else null + returned: When previous value is present on value change + type: str +diffs: + description: List of sync changes + returned: always + type: complex + contains: + path: + description: keypath to service changed + returned: always + type: str + diff: + description: configuration difference triggered the re-deploy + returned: always + type: str +commit_result: + description: Return values from commit operation + returned: always + type: complex + contains: + commit_queue: + description: Commit queue ID and status, if any + returned: When commit-queue is set in commit_flags + type: dict + sample: + - { + "commit_queue": { + "id": 1611776004976, + "status": "async" + } + } + +''' + +from ansible_collections.cisco.nso.plugins.module_utils.nso import connect, verify_version, nso_argument_spec +from ansible_collections.cisco.nso.plugins.module_utils.nso import State, ValueBuilder +from ansible_collections.cisco.nso.plugins.module_utils.nso import ModuleFailException, NsoException +from ansible.module_utils.basic import AnsibleModule + + +class NsoConfig(object): + REQUIRED_VERSIONS = [ + (4, 5), + (4, 4, 3), + (4, 3, 8), + (4, 2, 7), + (3, 4, 12) + ] + + def __init__(self, check_mode, client, data, commit_flags): + self._check_mode = check_mode + self._client = client + self._data = data + self._commit_flags = commit_flags + + self._changes = [] + self._diffs = [] + self._commit_result = [] + + def main(self): + # build list of values from configured data + value_builder = ValueBuilder(self._client) + for key, value in self._data.items(): + value_builder.build('', key, value) + + self._data_write(value_builder.values) + + # check sync AFTER configuration is written + sync_values = self._sync_check(value_builder.values) + self._sync_ensure(sync_values) + + return self._changes, self._diffs, self._commit_result + + def _data_write(self, values): + th = self._client.get_trans(mode='read_write') + + for value in values: + if value.state == State.SET: + self._client.set_value(th, value.path, value.value) + elif value.state == State.PRESENT: + self._client.create(th, value.path) + elif value.state == State.ABSENT: + self._client.delete(th, value.path) + + changes = self._client.get_trans_changes(th) + for change in changes: + if change['op'] == 'value_set': + self._changes.append({ + 'path': change['path'], + 'from': change['old'] or None, + 'to': change['value'], + 'type': 'set' + }) + elif change['op'] in ('created', 'deleted'): + self._changes.append({ + 'path': change['path'], + 'type': change['op'][:-1] + }) + + if len(changes) > 0: + # Fix for validate_commit method not working with commit flags prior to 5.4. + # If version < 5.4 then don't send the flags to validate_commit + version = float(self._client._version[0:self._client._version.find('.') + 2:]) + if version >= 5.4: + warnings = self._client.validate_commit(th, self._commit_flags) + else: + warnings = self._client.validate_commit(th) + if len(warnings) > 0: + raise NsoException( + 'failed to validate transaction with warnings: {0}'.format( + ', '.join((str(warning) for warning in warnings))), {}) + if self._check_mode or len(changes) == 0: + self._client.delete_trans(th) + else: + if self._commit_flags: + result = self._client.commit(th, self._commit_flags) + self._commit_result.append(result) + else: + result = self._client.commit(th) + self._commit_result.append(result) + + def _sync_check(self, values): + sync_values = [] + + for value in values: + if value.state in (State.CHECK_SYNC, State.IN_SYNC): + action = 'check-sync' + elif value.state in (State.DEEP_CHECK_SYNC, State.DEEP_IN_SYNC): + action = 'deep-check-sync' + else: + action = None + + if action is not None: + action_path = '{0}/{1}'.format(value.path, action) + action_params = {'outformat': 'cli'} + resp = self._client.run_action(None, action_path, action_params) + if len(resp) > 0: + sync_values.append( + ValueBuilder.Value(value.path, value.state, resp[0]['value'])) + + return sync_values + + def _sync_ensure(self, sync_values): + for value in sync_values: + if value.state in (State.CHECK_SYNC, State.DEEP_CHECK_SYNC): + raise NsoException( + '{0} out of sync, diff {1}'.format(value.path, value.value), {}) + + action_path = '{0}/{1}'.format(value.path, 're-deploy') + if not self._check_mode: + result = self._client.run_action(None, action_path) + if not result: + raise NsoException( + 'failed to re-deploy {0}'.format(value.path), {}) + + self._changes.append({'path': value.path, 'type': 're-deploy'}) + self._diffs.append({'path': value.path, 'diff': value.value}) + + +def main(): + argument_spec = dict( + data=dict(required=True, type='dict'), + commit_flags=dict(required=False, type='list', elements='str') + ) + + argument_spec.update(nso_argument_spec) + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True + ) + p = module.params + client = connect(p) + nso_config = NsoConfig(module.check_mode, client, p['data'], p['commit_flags']) + try: + verify_version(client, NsoConfig.REQUIRED_VERSIONS) + + changes, diffs, commit_result = nso_config.main() + client.logout() + + changed = len(changes) > 0 + module.exit_json( + changed=changed, changes=changes, diffs=diffs, commit_result=commit_result) + + except NsoException as ex: + client.logout() + module.fail_json(msg=ex.message) + except ModuleFailException as ex: + client.logout() + module.fail_json(msg=ex.message) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/cisco/nso/plugins/modules/nso_query.py b/collections-debian-merged/ansible_collections/cisco/nso/plugins/modules/nso_query.py new file mode 100644 index 00000000..5f2d26f5 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/plugins/modules/nso_query.py @@ -0,0 +1,129 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright (c) 2017 Cisco and/or its affiliates. +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. +# + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +DOCUMENTATION = ''' +--- +module: nso_query +extends_documentation_fragment: +- cisco.nso.nso + +short_description: Query data from Cisco NSO. +description: + - This module provides support for querying data from Cisco NSO using XPath. +requirements: + - Cisco NSO version 3.4 or higher. +author: "Claes Nästén (@cnasten)" +options: + xpath: + description: XPath selection relative to the root. + required: true + type: str + fields: + description: > + List of fields to select from matching nodes. + required: true + type: list + elements: str +''' + +EXAMPLES = ''' +- name: QUERY DEVICES DISPLAYING NAME AND DESCRIPTION + cisco.nso.nso_query: + url: https://10.10.20.49/jsonrpc + username: developer + password: C1sco12345 + xpath: /ncs:devices/device + fields: + - name + - description + register: nso_query_result + +- name: DISPLAY NSO_QUERY RESULT + debug: + var: nso_query_result +''' + +RETURN = ''' +output: + description: Value of matching nodes + returned: success + type: list +''' + +from ansible_collections.cisco.nso.plugins.module_utils.nso import connect, verify_version, nso_argument_spec +from ansible_collections.cisco.nso.plugins.module_utils.nso import ModuleFailException, NsoException +from ansible.module_utils.basic import AnsibleModule + + +class NsoQuery(object): + REQUIRED_VERSIONS = [ + (3, 4) + ] + + def __init__(self, check_mode, client, xpath, fields): + self._check_mode = check_mode + self._client = client + self._xpath = xpath + self._fields = fields + + def main(self): + if self._check_mode: + return [] + else: + return self._client.query(self._xpath, self._fields) + + +def main(): + argument_spec = dict( + xpath=dict(required=True, type='str'), + fields=dict(required=True, type='list', elements='str') + ) + argument_spec.update(nso_argument_spec) + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True + ) + p = module.params + + client = connect(p) + nso_query = NsoQuery( + module.check_mode, client, + p['xpath'], p['fields']) + try: + verify_version(client, NsoQuery.REQUIRED_VERSIONS) + + output = nso_query.main() + client.logout() + module.exit_json(changed=False, output=output) + except NsoException as ex: + client.logout() + module.fail_json(msg=ex.message) + except ModuleFailException as ex: + client.logout() + module.fail_json(msg=ex.message) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/cisco/nso/plugins/modules/nso_show.py b/collections-debian-merged/ansible_collections/cisco/nso/plugins/modules/nso_show.py new file mode 100644 index 00000000..e9d8963d --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/plugins/modules/nso_show.py @@ -0,0 +1,145 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright (c) 2017 Cisco and/or its affiliates. +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. +# + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +DOCUMENTATION = ''' +--- +module: nso_show +extends_documentation_fragment: +- cisco.nso.nso + +short_description: Displays data from Cisco NSO. +description: + - This module provides support for displaying data from Cisco NSO. +requirements: + - Cisco NSO version 3.4.12 or higher, 4.1.9 or higher, 4.2.6 or higher, + 4.3.7 or higher, 4.4.5 or higher, 4.5 or higher. +author: "Claes Nästén (@cnasten)" +options: + path: + description: Path to NSO data. + required: true + type: str + operational: + description: > + Controls whether or not operational data is included in the result. + type: bool + default: false +''' + +EXAMPLES = ''' +- name: DISPLAY DEVICE INCLUDING OPERATIONAL DATA + cisco.nso.nso_show: + url: https://10.10.20.49/jsonrpc + username: developer + password: C1sco12345 + path: /ncs:devices/device{dist-rtr01} + operational: true + register: result + +- name: Display the result + debug: + var: result + +- name: DISPLAY INTERFACES + cisco.nso.nso_show: + url: "https://10.10.20.49/jsonrpc" + username: developer + password: C1sco12345 + path: /ncs:devices/device{dist-rtr01}/config/interface + operational: true + register: result + +- name: Display the result + debug: + var: result +''' + +RETURN = ''' +output: + description: Configuration + returned: success + type: dict +''' + +from ansible_collections.cisco.nso.plugins.module_utils.nso import connect, verify_version, nso_argument_spec +from ansible_collections.cisco.nso.plugins.module_utils.nso import ModuleFailException, NsoException +from ansible.module_utils.basic import AnsibleModule + + +class NsoShow(object): + REQUIRED_VERSIONS = [ + (4, 5), + (4, 4, 5), + (4, 3, 7), + (4, 2, 6), + (4, 1, 9), + (3, 4, 12) + ] + + def __init__(self, check_mode, client, path, operational): + self._check_mode = check_mode + self._client = client + self._path = path + self._operational = operational + + def main(self): + if self._check_mode: + return {} + else: + return self._client.show_config(self._path, self._operational) + + +def main(): + argument_spec = dict( + path=dict(required=True, type='str'), + operational=dict(required=False, type='bool', default=False) + ) + argument_spec.update(nso_argument_spec) + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True + ) + p = module.params + + client = connect(p) + nso_show = NsoShow( + module.check_mode, client, + p['path'], p['operational']) + try: + verify_version(client, NsoShow.REQUIRED_VERSIONS) + + output = nso_show.main() + client.logout() + module.exit_json(changed=False, output=output) + except NsoException as ex: + client.logout() + module.fail_json(msg=ex.message) + except ModuleFailException as ex: + client.logout() + module.fail_json(msg=ex.message) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/cisco/nso/plugins/modules/nso_verify.py b/collections-debian-merged/ansible_collections/cisco/nso/plugins/modules/nso_verify.py new file mode 100644 index 00000000..03759706 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/plugins/modules/nso_verify.py @@ -0,0 +1,201 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright (c) 2017 Cisco and/or its affiliates. +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. +# + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +DOCUMENTATION = ''' +--- +module: nso_verify +extends_documentation_fragment: +- cisco.nso.nso + +short_description: Verifies Cisco NSO configuration. +description: + - This module provides support for verifying Cisco NSO configuration is in + compliance with specified values. +requirements: + - Cisco NSO version 3.4.12 or higher, 4.2.7 or higher, + 4.3.8 or higher, 4.4.3 or higher, 4.5 or higher. +author: "Claes Nästén (@cnasten)" +options: + data: + description: > + NSO data in format as C(| display json) converted to YAML. List entries can + be annotated with a C(__state) entry. Set to in-sync/deep-in-sync for + services to verify service is in sync with the network. Set to absent in + list entries to ensure they are deleted if they exist in NSO. + required: true + type: dict +''' + +EXAMPLES = ''' +- name: VERIFY INTERFACE IS ADMINISTRATIVELY UP + cisco.nso.nso_verify: + url: http://localhost:8080/jsonrpc + username: username + password: password + data: + tailf-ncs:devices: + device: + - name: dist-sw01 + config: + interface: + Ethernet: + - name: "1/1" + shutdown: false +''' + +RETURN = ''' +violations: + description: List of value violations + returned: failed + type: complex + sample: + - path: /ncs:devices/device{dist-sw01}/config/interface/Ethernet{1/1}/shutdown + expected-value: false + value: true + contains: + path: + description: Path to the value in violation + returned: always + type: str + expected-value: + description: Expected value of path + returned: always + type: str + value: + description: Current value of path + returned: always + type: str +''' + +from ansible_collections.cisco.nso.plugins.module_utils.nso import connect, verify_version, nso_argument_spec +from ansible_collections.cisco.nso.plugins.module_utils.nso import normalize_value +from ansible_collections.cisco.nso.plugins.module_utils.nso import State, ValueBuilder +from ansible_collections.cisco.nso.plugins.module_utils.nso import ModuleFailException, NsoException +from ansible.module_utils.basic import AnsibleModule + + +class NsoVerify(object): + REQUIRED_VERSIONS = [ + (4, 5), + (4, 4, 3), + (4, 3, 8), + (4, 2, 7), + (3, 4, 12) + ] + + def __init__(self, client, data): + self._client = client + self._data = data + + def main(self): + violations = [] + + # build list of values from configured data + value_builder = ValueBuilder(self._client, 'verify') + for key, value in self._data.items(): + value_builder.build('', key, value) + + for expected_value in value_builder.values: + if expected_value.state == State.PRESENT: + violations.append({ + 'path': expected_value.path, + 'expected-value': 'present', + 'value': 'absent' + }) + elif expected_value.state == State.ABSENT: + violations.append({ + 'path': expected_value.path, + 'expected-value': 'absent', + 'value': 'present' + }) + elif expected_value.state == State.SET: + try: + value = self._client.get_value(expected_value.path)['value'] + except NsoException as ex: + if ex.error.get('type', '') == 'data.not_found': + value = None + else: + raise + + # handle different types properly + n_value = normalize_value( + expected_value.value, value, expected_value.path) + if n_value != expected_value.value: + # if the value comparison fails, try mapping identityref + value_type = value_builder.get_type(expected_value.path) + if value_type is not None and 'identityref' in value_type: + n_value, t_value = self.get_prefix_name(value) + + if expected_value.value != n_value: + violations.append({ + 'path': expected_value.path, + 'expected-value': expected_value.value, + 'value': n_value + }) + else: + raise ModuleFailException( + 'value state {0} not supported at {1}'.format( + expected_value.state, expected_value.path)) + + return violations + + +def main(): + argument_spec = dict( + data=dict(required=True, type='dict') + ) + argument_spec.update(nso_argument_spec) + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True + ) + p = module.params + + client = connect(p) + nso_verify = NsoVerify(client, p['data']) + try: + verify_version(client, NsoVerify.REQUIRED_VERSIONS) + + violations = nso_verify.main() + client.logout() + + num_violations = len(violations) + if num_violations > 0: + msg = '{0} value{1} differ'.format( + num_violations, num_violations > 1 and 's' or '') + module.fail_json(msg=msg, violations=violations) + else: + module.exit_json(changed=False) + + except NsoException as ex: + client.logout() + module.fail_json(msg=ex.message) + except ModuleFailException as ex: + client.logout() + module.fail_json(msg=ex.message) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/__init__.py b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/__init__.py diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/compat/__init__.py b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/compat/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/compat/__init__.py diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/compat/builtins.py b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/compat/builtins.py new file mode 100644 index 00000000..f60ee678 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/compat/builtins.py @@ -0,0 +1,33 @@ +# (c) 2014, Toshio Kuratomi <tkuratomi@ansible.com> +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +# +# Compat for python2.7 +# + +# One unittest needs to import builtins via __import__() so we need to have +# the string that represents it +try: + import __builtin__ +except ImportError: + BUILTINS = 'builtins' +else: + BUILTINS = '__builtin__' diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/compat/mock.py b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/compat/mock.py new file mode 100644 index 00000000..0972cd2e --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/compat/mock.py @@ -0,0 +1,122 @@ +# (c) 2014, Toshio Kuratomi <tkuratomi@ansible.com> +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +''' +Compat module for Python3.x's unittest.mock module +''' +import sys + +# Python 2.7 + +# Note: Could use the pypi mock library on python3.x as well as python2.x. It +# is the same as the python3 stdlib mock library + +try: + # Allow wildcard import because we really do want to import all of mock's + # symbols into this compat shim + # pylint: disable=wildcard-import,unused-wildcard-import + from unittest.mock import * +except ImportError: + # Python 2 + # pylint: disable=wildcard-import,unused-wildcard-import + try: + from mock import * + except ImportError: + print('You need the mock library installed on python2.x to run tests') + + +# Prior to 3.4.4, mock_open cannot handle binary read_data +if sys.version_info >= (3,) and sys.version_info < (3, 4, 4): + file_spec = None + + def _iterate_read_data(read_data): + # Helper for mock_open: + # Retrieve lines from read_data via a generator so that separate calls to + # readline, read, and readlines are properly interleaved + sep = b'\n' if isinstance(read_data, bytes) else '\n' + data_as_list = [l + sep for l in read_data.split(sep)] + + if data_as_list[-1] == sep: + # If the last line ended in a newline, the list comprehension will have an + # extra entry that's just a newline. Remove this. + data_as_list = data_as_list[:-1] + else: + # If there wasn't an extra newline by itself, then the file being + # emulated doesn't have a newline to end the last line remove the + # newline that our naive format() added + data_as_list[-1] = data_as_list[-1][:-1] + + for line in data_as_list: + yield line + + def mock_open(mock=None, read_data=''): + """ + A helper function to create a mock to replace the use of `open`. It works + for `open` called directly or used as a context manager. + + The `mock` argument is the mock object to configure. If `None` (the + default) then a `MagicMock` will be created for you, with the API limited + to methods or attributes available on standard file handles. + + `read_data` is a string for the `read` methoddline`, and `readlines` of the + file handle to return. This is an empty string by default. + """ + def _readlines_side_effect(*args, **kwargs): + if handle.readlines.return_value is not None: + return handle.readlines.return_value + return list(_data) + + def _read_side_effect(*args, **kwargs): + if handle.read.return_value is not None: + return handle.read.return_value + return type(read_data)().join(_data) + + def _readline_side_effect(): + if handle.readline.return_value is not None: + while True: + yield handle.readline.return_value + for line in _data: + yield line + + global file_spec + if file_spec is None: + import _io + file_spec = list(set(dir(_io.TextIOWrapper)).union(set(dir(_io.BytesIO)))) + + if mock is None: + mock = MagicMock(name='open', spec=open) + + handle = MagicMock(spec=file_spec) + handle.__enter__.return_value = handle + + _data = _iterate_read_data(read_data) + + handle.write.return_value = None + handle.read.return_value = None + handle.readline.return_value = None + handle.readlines.return_value = None + + handle.read.side_effect = _read_side_effect + handle.readline.side_effect = _readline_side_effect() + handle.readlines.side_effect = _readlines_side_effect + + mock.return_value = handle + return mock diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/compat/unittest.py b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/compat/unittest.py new file mode 100644 index 00000000..98f08ad6 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/compat/unittest.py @@ -0,0 +1,38 @@ +# (c) 2014, Toshio Kuratomi <tkuratomi@ansible.com> +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +''' +Compat module for Python2.7's unittest module +''' + +import sys + +# Allow wildcard import because we really do want to import all of +# unittests's symbols into this compat shim +# pylint: disable=wildcard-import,unused-wildcard-import +if sys.version_info < (2, 7): + try: + # Need unittest2 on python2.6 + from unittest2 import * + except ImportError: + print('You need unittest2 installed on python2.6.x to run tests') +else: + from unittest import * diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/mock/__init__.py b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/mock/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/mock/__init__.py diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/mock/loader.py b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/mock/loader.py new file mode 100644 index 00000000..0ee47fbb --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/mock/loader.py @@ -0,0 +1,116 @@ +# (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com> +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os + +from ansible.errors import AnsibleParserError +from ansible.parsing.dataloader import DataLoader +from ansible.module_utils._text import to_bytes, to_text + + +class DictDataLoader(DataLoader): + + def __init__(self, file_mapping=None): + file_mapping = {} if file_mapping is None else file_mapping + assert type(file_mapping) == dict + + super(DictDataLoader, self).__init__() + + self._file_mapping = file_mapping + self._build_known_directories() + self._vault_secrets = None + + def load_from_file(self, path, cache=True, unsafe=False): + path = to_text(path) + if path in self._file_mapping: + return self.load(self._file_mapping[path], path) + return None + + # TODO: the real _get_file_contents returns a bytestring, so we actually convert the + # unicode/text it's created with to utf-8 + def _get_file_contents(self, path): + path = to_text(path) + if path in self._file_mapping: + return (to_bytes(self._file_mapping[path]), False) + else: + raise AnsibleParserError("file not found: %s" % path) + + def path_exists(self, path): + path = to_text(path) + return path in self._file_mapping or path in self._known_directories + + def is_file(self, path): + path = to_text(path) + return path in self._file_mapping + + def is_directory(self, path): + path = to_text(path) + return path in self._known_directories + + def list_directory(self, path): + ret = [] + path = to_text(path) + for x in (list(self._file_mapping.keys()) + self._known_directories): + if x.startswith(path): + if os.path.dirname(x) == path: + ret.append(os.path.basename(x)) + return ret + + def is_executable(self, path): + # FIXME: figure out a way to make paths return true for this + return False + + def _add_known_directory(self, directory): + if directory not in self._known_directories: + self._known_directories.append(directory) + + def _build_known_directories(self): + self._known_directories = [] + for path in self._file_mapping: + dirname = os.path.dirname(path) + while dirname not in ('/', ''): + self._add_known_directory(dirname) + dirname = os.path.dirname(dirname) + + def push(self, path, content): + rebuild_dirs = False + if path not in self._file_mapping: + rebuild_dirs = True + + self._file_mapping[path] = content + + if rebuild_dirs: + self._build_known_directories() + + def pop(self, path): + if path in self._file_mapping: + del self._file_mapping[path] + self._build_known_directories() + + def clear(self): + self._file_mapping = dict() + self._known_directories = [] + + def get_basedir(self): + return os.getcwd() + + def set_vault_secrets(self, vault_secrets): + self._vault_secrets = vault_secrets diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/mock/path.py b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/mock/path.py new file mode 100644 index 00000000..08b10e45 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/mock/path.py @@ -0,0 +1,8 @@ +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +from ansible_collections.cisco.nso.tests.unit.compat.mock import MagicMock +from ansible.utils.path import unfrackpath + + +mock_unfrackpath_noop = MagicMock(spec_set=unfrackpath, side_effect=lambda x, *args, **kwargs: x) diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/mock/procenv.py b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/mock/procenv.py new file mode 100644 index 00000000..bdd78c7f --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/mock/procenv.py @@ -0,0 +1,90 @@ +# (c) 2016, Matt Davis <mdavis@ansible.com> +# (c) 2016, Toshio Kuratomi <tkuratomi@ansible.com> +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import sys +import json + +from contextlib import contextmanager +from io import BytesIO, StringIO +from ansible_collections.cisco.nso.tests.unit.compat import unittest +from ansible.module_utils.six import PY3 +from ansible.module_utils._text import to_bytes + + +@contextmanager +def swap_stdin_and_argv(stdin_data='', argv_data=tuple()): + """ + context manager that temporarily masks the test runner's values for stdin and argv + """ + real_stdin = sys.stdin + real_argv = sys.argv + + if PY3: + fake_stream = StringIO(stdin_data) + fake_stream.buffer = BytesIO(to_bytes(stdin_data)) + else: + fake_stream = BytesIO(to_bytes(stdin_data)) + + try: + sys.stdin = fake_stream + sys.argv = argv_data + + yield + finally: + sys.stdin = real_stdin + sys.argv = real_argv + + +@contextmanager +def swap_stdout(): + """ + context manager that temporarily replaces stdout for tests that need to verify output + """ + old_stdout = sys.stdout + + if PY3: + fake_stream = StringIO() + else: + fake_stream = BytesIO() + + try: + sys.stdout = fake_stream + + yield fake_stream + finally: + sys.stdout = old_stdout + + +class ModuleTestCase(unittest.TestCase): + def setUp(self, module_args=None): + if module_args is None: + module_args = {'_ansible_remote_tmp': '/tmp', '_ansible_keep_remote_files': False} + + args = json.dumps(dict(ANSIBLE_MODULE_ARGS=module_args)) + + # unittest doesn't have a clean place to use a context manager, so we have to enter/exit manually + self.stdin_swap = swap_stdin_and_argv(stdin_data=args) + self.stdin_swap.__enter__() + + def tearDown(self): + # unittest doesn't have a clean place to use a context manager, so we have to enter/exit manually + self.stdin_swap.__exit__(None, None, None) diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/mock/vault_helper.py b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/mock/vault_helper.py new file mode 100644 index 00000000..dcce9c78 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/mock/vault_helper.py @@ -0,0 +1,39 @@ +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +from ansible.module_utils._text import to_bytes + +from ansible.parsing.vault import VaultSecret + + +class TextVaultSecret(VaultSecret): + '''A secret piece of text. ie, a password. Tracks text encoding. + + The text encoding of the text may not be the default text encoding so + we keep track of the encoding so we encode it to the same bytes.''' + + def __init__(self, text, encoding=None, errors=None, _bytes=None): + super(TextVaultSecret, self).__init__() + self.text = text + self.encoding = encoding or 'utf-8' + self._bytes = _bytes + self.errors = errors or 'strict' + + @property + def bytes(self): + '''The text encoded with encoding, unless we specifically set _bytes.''' + return self._bytes or to_bytes(self.text, encoding=self.encoding, errors=self.errors) diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/mock/yaml_helper.py b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/mock/yaml_helper.py new file mode 100644 index 00000000..bf0aa8d8 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/mock/yaml_helper.py @@ -0,0 +1,124 @@ +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +import io +import yaml + +from ansible.module_utils.six import PY3 +from ansible.parsing.yaml.loader import AnsibleLoader +from ansible.parsing.yaml.dumper import AnsibleDumper + + +class YamlTestUtils(object): + """Mixin class to combine with a unittest.TestCase subclass.""" + def _loader(self, stream): + """Vault related tests will want to override this. + + Vault cases should setup a AnsibleLoader that has the vault password.""" + return AnsibleLoader(stream) + + def _dump_stream(self, obj, stream, dumper=None): + """Dump to a py2-unicode or py3-string stream.""" + if PY3: + return yaml.dump(obj, stream, Dumper=dumper) + else: + return yaml.dump(obj, stream, Dumper=dumper, encoding=None) + + def _dump_string(self, obj, dumper=None): + """Dump to a py2-unicode or py3-string""" + if PY3: + return yaml.dump(obj, Dumper=dumper) + else: + return yaml.dump(obj, Dumper=dumper, encoding=None) + + def _dump_load_cycle(self, obj): + # Each pass though a dump or load revs the 'generation' + # obj to yaml string + string_from_object_dump = self._dump_string(obj, dumper=AnsibleDumper) + + # wrap a stream/file like StringIO around that yaml + stream_from_object_dump = io.StringIO(string_from_object_dump) + loader = self._loader(stream_from_object_dump) + # load the yaml stream to create a new instance of the object (gen 2) + obj_2 = loader.get_data() + + # dump the gen 2 objects directory to strings + string_from_object_dump_2 = self._dump_string(obj_2, + dumper=AnsibleDumper) + + # The gen 1 and gen 2 yaml strings + self.assertEqual(string_from_object_dump, string_from_object_dump_2) + # the gen 1 (orig) and gen 2 py object + self.assertEqual(obj, obj_2) + + # again! gen 3... load strings into py objects + stream_3 = io.StringIO(string_from_object_dump_2) + loader_3 = self._loader(stream_3) + obj_3 = loader_3.get_data() + + string_from_object_dump_3 = self._dump_string(obj_3, dumper=AnsibleDumper) + + self.assertEqual(obj, obj_3) + # should be transitive, but... + self.assertEqual(obj_2, obj_3) + self.assertEqual(string_from_object_dump, string_from_object_dump_3) + + def _old_dump_load_cycle(self, obj): + '''Dump the passed in object to yaml, load it back up, dump again, compare.''' + stream = io.StringIO() + + yaml_string = self._dump_string(obj, dumper=AnsibleDumper) + self._dump_stream(obj, stream, dumper=AnsibleDumper) + + yaml_string_from_stream = stream.getvalue() + + # reset stream + stream.seek(0) + + loader = self._loader(stream) + # loader = AnsibleLoader(stream, vault_password=self.vault_password) + obj_from_stream = loader.get_data() + + stream_from_string = io.StringIO(yaml_string) + loader2 = self._loader(stream_from_string) + # loader2 = AnsibleLoader(stream_from_string, vault_password=self.vault_password) + obj_from_string = loader2.get_data() + + stream_obj_from_stream = io.StringIO() + stream_obj_from_string = io.StringIO() + + if PY3: + yaml.dump(obj_from_stream, stream_obj_from_stream, Dumper=AnsibleDumper) + yaml.dump(obj_from_stream, stream_obj_from_string, Dumper=AnsibleDumper) + else: + yaml.dump(obj_from_stream, stream_obj_from_stream, Dumper=AnsibleDumper, encoding=None) + yaml.dump(obj_from_stream, stream_obj_from_string, Dumper=AnsibleDumper, encoding=None) + + yaml_string_stream_obj_from_stream = stream_obj_from_stream.getvalue() + yaml_string_stream_obj_from_string = stream_obj_from_string.getvalue() + + stream_obj_from_stream.seek(0) + stream_obj_from_string.seek(0) + + if PY3: + yaml_string_obj_from_stream = yaml.dump(obj_from_stream, Dumper=AnsibleDumper) + yaml_string_obj_from_string = yaml.dump(obj_from_string, Dumper=AnsibleDumper) + else: + yaml_string_obj_from_stream = yaml.dump(obj_from_stream, Dumper=AnsibleDumper, encoding=None) + yaml_string_obj_from_string = yaml.dump(obj_from_string, Dumper=AnsibleDumper, encoding=None) + + assert yaml_string == yaml_string_obj_from_stream + assert yaml_string == yaml_string_obj_from_stream == yaml_string_obj_from_string + assert (yaml_string == yaml_string_obj_from_stream == yaml_string_obj_from_string == yaml_string_stream_obj_from_stream == + yaml_string_stream_obj_from_string) + assert obj == obj_from_stream + assert obj == obj_from_string + assert obj == yaml_string_obj_from_stream + assert obj == yaml_string_obj_from_string + assert obj == obj_from_stream == obj_from_string == yaml_string_obj_from_stream == yaml_string_obj_from_string + return {'obj': obj, + 'yaml_string': yaml_string, + 'yaml_string_from_stream': yaml_string_from_stream, + 'obj_from_stream': obj_from_stream, + 'obj_from_string': obj_from_string, + 'yaml_string_obj_from_string': yaml_string_obj_from_string} diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/module_utils/__init__.py b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/module_utils/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/module_utils/__init__.py diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/module_utils/test_nso.py b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/module_utils/test_nso.py new file mode 100644 index 00000000..ee113aeb --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/module_utils/test_nso.py @@ -0,0 +1,660 @@ +# Copyright (c) 2017 Cisco and/or its affiliates. +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. +# + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +import json + +from ansible_collections.cisco.nso.tests.unit.compat.mock import patch +from ansible_collections.cisco.nso.tests.unit.compat import unittest +from ansible_collections.cisco.nso.plugins.module_utils import nso + + +MODULE_PREFIX_MAP = ''' +{ + "ansible-nso": "an", + "test": "test", + "tailf-ncs": "ncs" +} +''' + + +SCHEMA_DATA = { + '/an:id-name-leaf': ''' +{ + "meta": { + "prefix": "an", + "namespace": "http://github.com/ansible/nso", + "types": { + "http://github.com/ansible/nso:id-name-t": [ + { + "name": "http://github.com/ansible/nso:id-name-t", + "enumeration": [ + { + "label": "id-one" + }, + { + "label": "id-two" + } + ] + }, + { + "name": "identityref" + } + ] + }, + "keypath": "/an:id-name-leaf" + }, + "data": { + "kind": "leaf", + "type": { + "namespace": "http://github.com/ansible/nso", + "name": "id-name-t" + }, + "name": "id-name-leaf", + "qname": "an:id-name-leaf" + } +}''', + '/an:id-name-values': ''' +{ + "meta": { + "prefix": "an", + "namespace": "http://github.com/ansible/nso", + "types": {}, + "keypath": "/an:id-name-values" + }, + "data": { + "kind": "container", + "name": "id-name-values", + "qname": "an:id-name-values", + "children": [ + { + "kind": "list", + "name": "id-name-value", + "qname": "an:id-name-value", + "key": [ + "name" + ] + } + ] + } +} +''', + '/an:id-name-values/id-name-value': ''' +{ + "meta": { + "prefix": "an", + "namespace": "http://github.com/ansible/nso", + "types": { + "http://github.com/ansible/nso:id-name-t": [ + { + "name": "http://github.com/ansible/nso:id-name-t", + "enumeration": [ + { + "label": "id-one" + }, + { + "label": "id-two" + } + ] + }, + { + "name": "identityref" + } + ] + }, + "keypath": "/an:id-name-values/id-name-value" + }, + "data": { + "kind": "list", + "name": "id-name-value", + "qname": "an:id-name-value", + "key": [ + "name" + ], + "children": [ + { + "kind": "key", + "name": "name", + "qname": "an:name", + "type": { + "namespace": "http://github.com/ansible/nso", + "name": "id-name-t" + } + }, + { + "kind": "leaf", + "type": { + "primitive": true, + "name": "string" + }, + "name": "value", + "qname": "an:value" + } + ] + } +} +''', + '/test:test': ''' +{ + "meta": { + "types": { + "http://example.com/test:t15": [ + { + "leaf_type":[ + { + "name":"string" + } + ], + "list_type":[ + { + "name":"http://example.com/test:t15", + "leaf-list":true + } + ] + } + ] + } + }, + "data": { + "kind": "list", + "name":"test", + "qname":"test:test", + "key":["name"], + "children": [ + { + "kind": "key", + "name": "name", + "qname": "test:name", + "type": {"name":"string","primitive":true} + }, + { + "kind": "choice", + "name": "test-choice", + "qname": "test:test-choice", + "cases": [ + { + "kind": "case", + "name": "direct-child-case", + "qname":"test:direct-child-case", + "children":[ + { + "kind": "leaf", + "name": "direct-child", + "qname": "test:direct-child", + "type": {"name":"string","primitive":true} + } + ] + }, + { + "kind":"case","name":"nested-child-case","qname":"test:nested-child-case", + "children": [ + { + "kind": "choice", + "name": "nested-choice", + "qname": "test:nested-choice", + "cases": [ + { + "kind":"case","name":"nested-child","qname":"test:nested-child", + "children": [ + { + "kind": "leaf", + "name":"nested-child", + "qname":"test:nested-child", + "type":{"name":"string","primitive":true}} + ] + } + ] + } + ] + } + ] + }, + { + "kind":"leaf-list", + "name":"device-list", + "qname":"test:device-list", + "type": { + "namespace":"http://example.com/test", + "name":"t15" + } + } + ] + } +} +''', + '/test:test/device-list': ''' +{ + "meta": { + "types": { + "http://example.com/test:t15": [ + { + "leaf_type":[ + { + "name":"string" + } + ], + "list_type":[ + { + "name":"http://example.com/test:t15", + "leaf-list":true + } + ] + } + ] + } + }, + "data": { + "kind":"leaf-list", + "name":"device-list", + "qname":"test:device-list", + "type": { + "namespace":"http://example.com/test", + "name":"t15" + } + } +} +''', + '/test:deps': ''' +{ + "meta": { + }, + "data": { + "kind":"container", + "name":"deps", + "qname":"test:deps", + "children": [ + { + "kind": "leaf", + "type": { + "primitive": true, + "name": "string" + }, + "name": "a", + "qname": "test:a", + "deps": ["/test:deps/c"] + }, + { + "kind": "leaf", + "type": { + "primitive": true, + "name": "string" + }, + "name": "b", + "qname": "test:b", + "deps": ["/test:deps/a"] + }, + { + "kind": "leaf", + "type": { + "primitive": true, + "name": "string" + }, + "name": "c", + "qname": "test:c" + } + ] + } +} +''' +} + + +class MockResponse(object): + def __init__(self, method, params, code, body, headers=None): + if headers is None: + headers = {} + + self.method = method + self.params = params + + self.code = code + self.body = body + self.headers = dict(headers) + + def read(self): + return self.body + + +def mock_call(calls, url, timeout, validate_certs, data=None, headers=None, method=None): + result = calls[0] + del calls[0] + + request = json.loads(data) + if result.method != request['method']: + raise ValueError('expected method {0}({1}), got {2}({3})'.format( + result.method, result.params, + request['method'], request['params'])) + + for key, value in result.params.items(): + if key not in request['params']: + raise ValueError('{0} not in parameters'.format(key)) + if value != request['params'][key]: + raise ValueError('expected {0} to be {1}, got {2}'.format( + key, value, request['params'][key])) + + return result + + +def get_schema_response(path): + return MockResponse( + 'get_schema', {'path': path}, 200, '{{"result": {0}}}'.format( + SCHEMA_DATA[path])) + + +class TestJsonRpc(unittest.TestCase): + @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url') + def test_exists(self, open_url_mock): + calls = [ + MockResponse('new_trans', {}, 200, '{"result": {"th": 1}}'), + MockResponse('exists', {'path': '/exists'}, 200, '{"result": {"exists": true}}'), + MockResponse('exists', {'path': '/not-exists'}, 200, '{"result": {"exists": false}}') + ] + open_url_mock.side_effect = lambda *args, **kwargs: mock_call(calls, *args, **kwargs) + client = nso.JsonRpc('http://localhost:8080/jsonrpc', 10, False) + self.assertEqual(True, client.exists('/exists')) + self.assertEqual(False, client.exists('/not-exists')) + + self.assertEqual(0, len(calls)) + + @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url') + def test_exists_data_not_found(self, open_url_mock): + calls = [ + MockResponse('new_trans', {}, 200, '{"result": {"th": 1}}'), + MockResponse('exists', {'path': '/list{missing-parent}/list{child}'}, 200, '{"error":{"type":"data.not_found"}}') + ] + open_url_mock.side_effect = lambda *args, **kwargs: mock_call(calls, *args, **kwargs) + client = nso.JsonRpc('http://localhost:8080/jsonrpc', 10, False) + self.assertEqual(False, client.exists('/list{missing-parent}/list{child}')) + + self.assertEqual(0, len(calls)) + + +class TestValueBuilder(unittest.TestCase): + @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url') + def test_identityref_leaf(self, open_url_mock): + calls = [ + MockResponse('get_system_setting', {'operation': 'version'}, 200, '{"result": "4.5"}'), + MockResponse('new_trans', {}, 200, '{"result": {"th": 1}}'), + get_schema_response('/an:id-name-leaf'), + MockResponse('get_module_prefix_map', {}, 200, '{{"result": {0}}}'.format(MODULE_PREFIX_MAP)) + ] + open_url_mock.side_effect = lambda *args, **kwargs: mock_call(calls, *args, **kwargs) + + parent = "/an:id-name-leaf" + schema_data = json.loads( + SCHEMA_DATA['/an:id-name-leaf']) + schema = schema_data['data'] + + vb = nso.ValueBuilder(nso.JsonRpc('http://localhost:8080/jsonrpc', 10, False)) + vb.build(parent, None, 'ansible-nso:id-two', schema) + values = list(vb.values) + self.assertEqual(1, len(values)) + value = values[0] + self.assertEqual(parent, value.path) + self.assertEqual('set', value.state) + self.assertEqual('an:id-two', value.value) + + self.assertEqual(0, len(calls)) + + @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url') + def test_identityref_key(self, open_url_mock): + calls = [ + MockResponse('get_system_setting', {'operation': 'version'}, 200, '{"result": "4.5"}'), + MockResponse('new_trans', {}, 200, '{"result": {"th": 1}}'), + get_schema_response('/an:id-name-values/id-name-value'), + MockResponse('get_module_prefix_map', {}, 200, '{{"result": {0}}}'.format(MODULE_PREFIX_MAP)), + MockResponse('exists', {'path': '/an:id-name-values/id-name-value{an:id-one}'}, 200, '{"result": {"exists": true}}') + ] + open_url_mock.side_effect = lambda *args, **kwargs: mock_call(calls, *args, **kwargs) + + parent = "/an:id-name-values" + schema_data = json.loads( + SCHEMA_DATA['/an:id-name-values/id-name-value']) + schema = schema_data['data'] + + vb = nso.ValueBuilder(nso.JsonRpc('http://localhost:8080/jsonrpc', 10, False)) + vb.build(parent, 'id-name-value', [{'name': 'ansible-nso:id-one', 'value': '1'}], schema) + values = list(vb.values) + self.assertEqual(1, len(values)) + value = values[0] + self.assertEqual('{0}/id-name-value{{an:id-one}}/value'.format(parent), value.path) + self.assertEqual('set', value.state) + self.assertEqual('1', value.value) + + self.assertEqual(0, len(calls)) + + @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url') + def test_nested_choice(self, open_url_mock): + calls = [ + MockResponse('get_system_setting', {'operation': 'version'}, 200, '{"result": "4.5"}'), + MockResponse('new_trans', {}, 200, '{"result": {"th": 1}}'), + get_schema_response('/test:test'), + MockResponse('exists', {'path': '/test:test{direct}'}, 200, '{"result": {"exists": true}}'), + MockResponse('exists', {'path': '/test:test{nested}'}, 200, '{"result": {"exists": true}}') + ] + open_url_mock.side_effect = lambda *args, **kwargs: mock_call(calls, *args, **kwargs) + + parent = "/test:test" + schema_data = json.loads( + SCHEMA_DATA['/test:test']) + schema = schema_data['data'] + + vb = nso.ValueBuilder(nso.JsonRpc('http://localhost:8080/jsonrpc', 10, False)) + vb.build(parent, None, [{'name': 'direct', 'direct-child': 'direct-value'}, + {'name': 'nested', 'nested-child': 'nested-value'}], schema) + values = list(vb.values) + self.assertEqual(2, len(values)) + value = values[0] + self.assertEqual('{0}{{direct}}/direct-child'.format(parent), value.path) + self.assertEqual('set', value.state) + self.assertEqual('direct-value', value.value) + + value = values[1] + self.assertEqual('{0}{{nested}}/nested-child'.format(parent), value.path) + self.assertEqual('set', value.state) + self.assertEqual('nested-value', value.value) + + self.assertEqual(0, len(calls)) + + @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url') + def test_leaf_list_type(self, open_url_mock): + calls = [ + MockResponse('get_system_setting', {'operation': 'version'}, 200, '{"result": "4.4"}'), + MockResponse('new_trans', {}, 200, '{"result": {"th": 1}}'), + get_schema_response('/test:test') + ] + open_url_mock.side_effect = lambda *args, **kwargs: mock_call(calls, *args, **kwargs) + + parent = "/test:test" + schema_data = json.loads( + SCHEMA_DATA['/test:test']) + schema = schema_data['data'] + + vb = nso.ValueBuilder(nso.JsonRpc('http://localhost:8080/jsonrpc', 10, False)) + vb.build(parent, None, {'device-list': ['one', 'two']}, schema) + values = list(vb.values) + self.assertEqual(1, len(values)) + value = values[0] + self.assertEqual('{0}/device-list'.format(parent), value.path) + self.assertEqual(['one', 'two'], value.value) + + self.assertEqual(0, len(calls)) + + @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url') + def test_leaf_list_type_45(self, open_url_mock): + calls = [ + MockResponse('get_system_setting', {'operation': 'version'}, 200, '{"result": "4.5"}'), + MockResponse('new_trans', {}, 200, '{"result": {"th": 1}}'), + get_schema_response('/test:test/device-list') + ] + open_url_mock.side_effect = lambda *args, **kwargs: mock_call(calls, *args, **kwargs) + + parent = "/test:test" + schema_data = json.loads( + SCHEMA_DATA['/test:test']) + schema = schema_data['data'] + + vb = nso.ValueBuilder(nso.JsonRpc('http://localhost:8080/jsonrpc', 10, False)) + vb.build(parent, None, {'device-list': ['one', 'two']}, schema) + values = list(vb.values) + self.assertEqual(3, len(values)) + value = values[0] + self.assertEqual('{0}/device-list'.format(parent), value.path) + self.assertEqual(nso.State.ABSENT, value.state) + value = values[1] + self.assertEqual('{0}/device-list{{one}}'.format(parent), value.path) + self.assertEqual(nso.State.PRESENT, value.state) + value = values[2] + self.assertEqual('{0}/device-list{{two}}'.format(parent), value.path) + self.assertEqual(nso.State.PRESENT, value.state) + + self.assertEqual(0, len(calls)) + + @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url') + def test_sort_by_deps(self, open_url_mock): + calls = [ + MockResponse('get_system_setting', {'operation': 'version'}, 200, '{"result": "4.5"}'), + MockResponse('new_trans', {}, 200, '{"result": {"th": 1}}'), + get_schema_response('/test:deps') + ] + open_url_mock.side_effect = lambda *args, **kwargs: mock_call(calls, *args, **kwargs) + + parent = "/test:deps" + schema_data = json.loads( + SCHEMA_DATA['/test:deps']) + schema = schema_data['data'] + + values = { + 'a': '1', + 'b': '2', + 'c': '3', + } + + vb = nso.ValueBuilder(nso.JsonRpc('http://localhost:8080/jsonrpc', 10, False)) + vb.build(parent, None, values, schema) + values = list(vb.values) + self.assertEqual(3, len(values)) + value = values[0] + self.assertEqual('{0}/c'.format(parent), value.path) + self.assertEqual('3', value.value) + value = values[1] + self.assertEqual('{0}/a'.format(parent), value.path) + self.assertEqual('1', value.value) + value = values[2] + self.assertEqual('{0}/b'.format(parent), value.path) + self.assertEqual('2', value.value) + + self.assertEqual(0, len(calls)) + + @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url') + def test_sort_by_deps_not_included(self, open_url_mock): + calls = [ + MockResponse('get_system_setting', {'operation': 'version'}, 200, '{"result": "4.5"}'), + MockResponse('new_trans', {}, 200, '{"result": {"th": 1}}'), + get_schema_response('/test:deps') + ] + open_url_mock.side_effect = lambda *args, **kwargs: mock_call(calls, *args, **kwargs) + + parent = "/test:deps" + schema_data = json.loads( + SCHEMA_DATA['/test:deps']) + schema = schema_data['data'] + + values = { + 'a': '1', + 'b': '2' + } + + vb = nso.ValueBuilder(nso.JsonRpc('http://localhost:8080/jsonrpc', 10, False)) + vb.build(parent, None, values, schema) + values = list(vb.values) + self.assertEqual(2, len(values)) + value = values[0] + self.assertEqual('{0}/a'.format(parent), value.path) + self.assertEqual('1', value.value) + value = values[1] + self.assertEqual('{0}/b'.format(parent), value.path) + self.assertEqual('2', value.value) + + self.assertEqual(0, len(calls)) + + +class TestVerifyVersion(unittest.TestCase): + def test_valid_versions(self): + self.assertTrue(nso.verify_version_str('5.0', [(4, 6), (4, 5, 1)])) + self.assertTrue(nso.verify_version_str('5.1.1', [(4, 6), (4, 5, 1)])) + self.assertTrue(nso.verify_version_str('5.1.1.2', [(4, 6), (4, 5, 1)])) + self.assertTrue(nso.verify_version_str('4.6', [(4, 6), (4, 5, 1)])) + self.assertTrue(nso.verify_version_str('4.6.2', [(4, 6), (4, 5, 1)])) + self.assertTrue(nso.verify_version_str('4.6.2.1', [(4, 6), (4, 5, 1)])) + self.assertTrue(nso.verify_version_str('4.5.1', [(4, 6), (4, 5, 1)])) + self.assertTrue(nso.verify_version_str('4.5.2', [(4, 6), (4, 5, 1)])) + self.assertTrue(nso.verify_version_str('4.5.1.2', [(4, 6), (4, 5, 1)])) + + def test_invalid_versions(self): + self.assertFalse(nso.verify_version_str('4.4', [(4, 6), (4, 5, 1)])) + self.assertFalse(nso.verify_version_str('4.4.1', [(4, 6), (4, 5, 1)])) + self.assertFalse(nso.verify_version_str('4.4.1.2', [(4, 6), (4, 5, 1)])) + self.assertFalse(nso.verify_version_str('4.5.0', [(4, 6), (4, 5, 1)])) + + +class TestValueSort(unittest.TestCase): + def test_sort_parent_depend(self): + values = [ + nso.ValueBuilder.Value('/test/list{entry}', '/test/list', 'CREATE', ['']), + nso.ValueBuilder.Value('/test/list{entry}/description', '/test/list/description', 'TEST', ['']), + nso.ValueBuilder.Value('/test/entry', '/test/entry', 'VALUE', ['/test/list', '/test/list/name']) + ] + + result = [v.path for v in nso.ValueBuilder.sort_values(values)] + + self.assertEqual(['/test/list{entry}', '/test/entry', '/test/list{entry}/description'], result) + + def test_sort_break_direct_cycle(self): + values = [ + nso.ValueBuilder.Value('/test/a', '/test/a', 'VALUE', ['/test/c']), + nso.ValueBuilder.Value('/test/b', '/test/b', 'VALUE', ['/test/a']), + nso.ValueBuilder.Value('/test/c', '/test/c', 'VALUE', ['/test/a']) + ] + + result = [v.path for v in nso.ValueBuilder.sort_values(values)] + + self.assertEqual(['/test/a', '/test/b', '/test/c'], result) + + def test_sort_break_indirect_cycle(self): + values = [ + nso.ValueBuilder.Value('/test/c', '/test/c', 'VALUE', ['/test/a']), + nso.ValueBuilder.Value('/test/a', '/test/a', 'VALUE', ['/test/b']), + nso.ValueBuilder.Value('/test/b', '/test/b', 'VALUE', ['/test/c']) + ] + + result = [v.path for v in nso.ValueBuilder.sort_values(values)] + + self.assertEqual(['/test/a', '/test/c', '/test/b'], result) + + def test_sort_depend_on_self(self): + values = [ + nso.ValueBuilder.Value('/test/a', '/test/a', 'VALUE', ['/test/a']), + nso.ValueBuilder.Value('/test/b', '/test/b', 'VALUE', []) + ] + + result = [v.path for v in nso.ValueBuilder.sort_values(values)] + + self.assertEqual(['/test/a', '/test/b'], result) diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/__init__.py b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/__init__.py diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/complex_schema.json b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/complex_schema.json new file mode 100644 index 00000000..49a11765 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/complex_schema.json @@ -0,0 +1,212 @@ +{ + "meta": { + "prefix": "ansible", + "namespace": "http://example.com/ansible", + "types": { + }, + "keypath": "/ansible:action/complex" + }, + "data": { + "kind": "action", + "mandatory": true, + "name": "complex", + "qname": "ansible:complex", + "access": { + "read": false, + "create": false, + "execute": true, + "update": false, + "delete": false + }, + "children": [ + { + "kind": "leaf", + "is_action_input": true, + "name": "number", + "qname": "ansible:number", + "access": { + "read": false, + "create": false, + "execute": false, + "update": true, + "delete": false + }, + "type": { + "primitive": true, + "name": "uint8" + } + }, + { + "kind": "container", + "is_action_input": true, + "mandatory": true, + "name": "ansible", + "qname": "ansible:ansible", + "access": { + "read": false, + "create": false, + "execute": false, + "update": true, + "delete": false + }, + "children": [ + { + "kind": "choice", + "cases": [ + { + "kind": "case", + "name": "version", + "children": [ + { + "kind": "leaf", + "is_action_input": true, + "name": "version", + "qname": "ansible:version", + "access": { + "read": false, + "create": false, + "execute": false, + "update": true, + "delete": false + }, + "type": { + "primitive": true, + "name": "string" + } + } + ] + }, + { + "kind": "case", + "name": "release", + "children": [ + { + "kind": "container", + "is_action_input": true, + "mandatory": true, + "name": "release", + "qname": "ansible:release", + "access": { + "read": false, + "create": false, + "execute": false, + "update": true, + "delete": false + }, + "children": [ + { + "kind": "leaf", + "is_action_input": true, + "name": "major", + "qname": "ansible:major", + "access": { + "read": false, + "create": false, + "execute": false, + "update": true, + "delete": false + }, + "type": { + "primitive": true, + "name": "uint8" + } + }, + { + "kind": "leaf", + "is_action_input": true, + "name": "minor", + "qname": "ansible:minor", + "access": { + "read": false, + "create": false, + "execute": false, + "update": true, + "delete": false + }, + "type": { + "primitive": true, + "name": "uint8" + } + } + ] + } + ] + } + ], + "name": "version-releae-choice" + } + ] + }, + { + "kind": "choice", + "cases": [ + { + "kind": "case", + "name": "version", + "children": [ + { + "kind": "list", + "min_elements": 0, + "name": "version", + "max_elements": "unbounded", + "qname": "ansible:version", + "access": { + "read": false, + "create": false, + "execute": false, + "update": false, + "delete": false + }, + "mandatory": true, + "children": [ + { + "kind": "leaf", + "name": "name", + "qname": "ansible:name", + "access": { + "read": false, + "create": false, + "execute": false, + "update": false, + "delete": false + }, + "type": { + "primitive": true, + "name": "string" + }, + "is_action_output": true + } + ], + "is_action_output": true + } + ] + }, + { + "kind": "case", + "name": "release", + "children": [ + { + "kind": "leaf", + "name": "release", + "qname": "ansible:release", + "access": { + "read": false, + "create": false, + "execute": false, + "update": false, + "delete": false + }, + "type": { + "primitive": true, + "name": "string" + }, + "is_action_output": true + } + ] + } + ], + "name": "version-release-choice" + } + ] + } +} diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/config_config.json b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/config_config.json new file mode 100644 index 00000000..b7318586 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/config_config.json @@ -0,0 +1,20 @@ +{ + "l3vpn:vpn": { + "l3vpn": [ + { + "name": "company", + "route-distinguisher": 999, + "endpoint": [ + { + "id": "branch-office1", + "ce-device": "ce6", + "ce-interface": "GigabitEthernet0/12", + "ip-network": "10.10.1.0/24", + "bandwidth": 12000000, + "as-number": 65101 + } + ] + } + ] + } +} diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/config_config_changes.json b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/config_config_changes.json new file mode 100644 index 00000000..3ef234b7 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/config_config_changes.json @@ -0,0 +1,46 @@ +{ + "changes": [ + { + "path": "/l3vpn:vpn/l3vpn{company}/endpoint{branch-office1}/ce-device", + "old": "", + "value": "ce6", + "op": "value_set" + }, + { + "path": "/l3vpn:vpn/l3vpn{company}/endpoint{branch-office1}/ip-network", + "old": "", + "value": "10.10.1.0/24", + "op": "value_set" + }, + { + "path": "/l3vpn:vpn/l3vpn{company}/endpoint{branch-office1}/as-number", + "old": "", + "value": "65101", + "op": "value_set" + }, + { + "path": "/l3vpn:vpn/l3vpn{company}/endpoint{branch-office1}/ce-interface", + "old": "", + "value": "GigabitEthernet0/12", + "op": "value_set" + }, + { + "path": "/l3vpn:vpn/l3vpn{company}/endpoint{branch-office1}/bandwidth", + "old": "", + "value": "12000000", + "op": "value_set" + }, + { + "path": "/l3vpn:vpn/l3vpn{company}/endpoint{branch-office1}", + "old": "", + "value": "", + "op": "created" + }, + { + "path": "/l3vpn:vpn/l3vpn{company}", + "old": "", + "value": "", + "op": "modified" + } + ] +} diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/config_empty_data.json b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/config_empty_data.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/config_empty_data.json @@ -0,0 +1 @@ +{} diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/description_schema.json b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/description_schema.json new file mode 100644 index 00000000..2680a484 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/description_schema.json @@ -0,0 +1,28 @@ +{ + "meta": { + "prefix": "ncs", + "namespace": "http://tail-f.com/ns/ncs", + "types": { + }, + "keypath": "/ncs:devices/device{ce0}/description" + }, + "data": { + "info": { + "string": "Free form textual description" + }, + "kind": "leaf", + "name": "description", + "qname": "ncs:description", + "access": { + "read": true, + "create": true, + "execute": false, + "update": true, + "delete": true + }, + "type": { + "primitive": true, + "name": "string" + } + } +} diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/device_schema.json b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/device_schema.json new file mode 100644 index 00000000..d3bd2ac3 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/device_schema.json @@ -0,0 +1 @@ +{"meta": {"prefix": "ncs", "namespace": "http://tail-f.com/ns/ncs", "types": {"http://tail-f.com/ns/ncs:t85": [{"list_type": [{"leaf-list": true, "name": "http://tail-f.com/ns/ncs:t85"}], "leaf_type": [{"name": "string"}]}], "urn:ietf:params:xml:ns:yang:ietf-inet-types:port-number": [{"range": {"value": [["0", "65535"]]}, "name": "urn:ietf:params:xml:ns:yang:ietf-inet-types:port-number"}, {"name": "uint16"}], "http://tail-f.com/ns/ncs:t83": [{"list_type": [{"leaf-list": true, "name": "http://tail-f.com/ns/ncs:t83"}], "leaf_type": [{"name": "string"}]}], "http://tail-f.com/ns/ncs:node-name": [{"name": "http://tail-f.com/ns/ncs:node-name"}, {"max-length": {"value": 253}, "min-length": {"value": 1}, "name": "urn:ietf:params:xml:ns:yang:ietf-inet-types:domain-name", "pattern": {"value": "((([a-zA-Z0-9_]([a-zA-Z0-9\\-_]){0,61})?[a-zA-Z0-9]\\.)*([a-zA-Z0-9_]([a-zA-Z0-9\\-_]){0,61})?[a-zA-Z0-9]\\.?)|\\."}}, {"name": "string"}], "http://tail-f.com/ns/ncs:t29": [{"range": {"value": [["1", "4294967"]]}, "name": "http://tail-f.com/ns/ncs:t29"}, {"name": "uint32"}], "http://tail-f.com/ns/ncs:t101": [{"list_type": [{"leaf-list": true, "name": "http://tail-f.com/ns/ncs:t101"}], "leaf_type": [{"name": "string"}]}], "http://tail-f.com/ns/ncs:t43": [{"list_type": [{"leaf-list": true, "name": "http://tail-f.com/ns/ncs:t43"}], "leaf_type": [{"name": "string"}]}], "http://tail-f.com/ns/ncs:t27": [{"range": {"value": [["1", "4294967"]]}, "name": "http://tail-f.com/ns/ncs:t27"}, {"name": "uint32"}], "http://tail-f.com/ns/ncs:t40": [{"name": "http://tail-f.com/ns/ncs:t40", "enumeration": [{"label": "reject"}, {"label": "accept"}]}, {"name": "string"}], "http://tail-f.com/ns/ncs:t47": [{"list_type": [{"leaf-list": true, "name": "http://tail-f.com/ns/ncs:t47"}], "leaf_type": [{"name": "string"}]}], "urn:ietf:params:xml:ns:yang:ietf-inet-types:host": [{"union": [[{"name": "urn:ietf:params:xml:ns:yang:ietf-inet-types:ip-address"}, {"name": "ip-address"}], [{"max-length": {"value": 253}, "min-length": {"value": 1}, "name": "urn:ietf:params:xml:ns:yang:ietf-inet-types:domain-name", "pattern": {"value": "((([a-zA-Z0-9_]([a-zA-Z0-9\\-_]){0,61})?[a-zA-Z0-9]\\.)*([a-zA-Z0-9_]([a-zA-Z0-9\\-_]){0,61})?[a-zA-Z0-9]\\.?)|\\."}}, {"name": "string"}]]}], "http://tail-f.com/ns/ncs:t45": [{"list_type": [{"leaf-list": true, "name": "http://tail-f.com/ns/ncs:t45"}], "leaf_type": [{"name": "string"}]}], "http://tail-f.com/ns/ncs:t49": [{"list_type": [{"leaf-list": true, "name": "http://tail-f.com/ns/ncs:t49"}], "leaf_type": [{"name": "string"}]}], "http://tail-f.com/ns/ncs:trace-flag": [{"name": "http://tail-f.com/ns/ncs:trace-flag", "enumeration": [{"info": "Trace is disabled", "label": "false"}, {"info": "Raw, unformatted data", "label": "raw"}, {"info": "Pretty-printed data", "label": "pretty"}]}, {"name": "string"}], "http://tail-f.com/ns/ncs:t28": [{"range": {"value": [["1", "4294967"]]}, "name": "http://tail-f.com/ns/ncs:t28"}, {"name": "uint32"}]}, "keypath": "/ncs:devices/device"}, "data": {"info": {"string": "The list of managed devices"}, "kind": "list", "leafref_groups": [["remote-node"], ["authgroup"], ["device-profile"]], "mandatory": true, "name": "device", "max_elements": "unbounded", "contains_when_statement": true, "qname": "ncs:device", "children": [{"info": {"string": "A string uniquely identifying the managed device"}, "kind": "key", "mandatory": true, "name": "name", "qname": "ncs:name", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "string"}}, {"info": {"string": "IP address or host name for the management interface"}, "kind": "leaf", "name": "address", "qname": "ncs:address", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"namespace": "urn:ietf:params:xml:ns:yang:ietf-inet-types", "name": "host"}}, {"info": {"string": "Port for the management interface"}, "kind": "leaf", "name": "port", "qname": "ncs:port", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"namespace": "urn:ietf:params:xml:ns:yang:ietf-inet-types", "name": "port-number"}}, {"info": {"string": "Name of remote node which connects to device"}, "kind": "leaf", "name": "remote-node", "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "node-name"}, "qname": "ncs:remote-node", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "leafref_target": "/ncs:cluster/remote-node/name", "is_leafref": true}, {"info": {"string": "SSH connection configuration"}, "kind": "container", "mandatory": true, "name": "ssh", "qname": "ncs:ssh", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "Free form textual description"}, "kind": "leaf", "name": "description", "qname": "ncs:description", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"primitive": true, "name": "string"}}, {"info": {"string": "Physical location of devices in the group"}, "kind": "container", "mandatory": true, "name": "location", "qname": "ncs:location", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "Authentication credentials for the device"}, "kind": "leaf", "name": "authgroup", "type": {"primitive": true, "name": "string"}, "qname": "ncs:authgroup", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "leafref_target": "/ncs:devices/authgroups/group/name", "is_leafref": true}, {"info": {"string": "Management protocol for the device"}, "kind": "container", "mandatory": true, "name": "device-type", "qname": "ncs:device-type", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"kind": "leaf", "name": "device-profile", "type": {"primitive": true, "name": "string"}, "qname": "ncs:device-profile", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "leafref_target": "/ncs:devices/profiles/profile/name", "is_leafref": true}, {"info": {"string": "Timeout in seconds for new connections"}, "kind": "leaf", "name": "connect-timeout", "qname": "ncs:connect-timeout", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "units": "seconds", "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t27"}}, {"info": {"string": "Timeout in seconds used when reading data"}, "kind": "leaf", "name": "read-timeout", "qname": "ncs:read-timeout", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "units": "seconds", "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t28"}}, {"info": {"string": "Timeout in seconds used when writing data"}, "kind": "leaf", "name": "write-timeout", "qname": "ncs:write-timeout", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "units": "seconds", "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t29"}}, {"info": {"string": "Controls SSH keep alive settings"}, "kind": "container", "mandatory": true, "name": "ssh-keep-alive", "qname": "ncs:ssh-keep-alive", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "Trace the southbound communication to devices"}, "kind": "leaf", "name": "trace", "qname": "ncs:trace", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "trace-flag"}}, {"info": {"string": "Control which device capabilities NCS uses"}, "kind": "container", "mandatory": true, "name": "ned-settings", "qname": "ncs:ned-settings", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "Control settings for the commit-queue"}, "kind": "container", "mandatory": true, "name": "commit-queue", "qname": "ncs:commit-queue", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "Control how sessions to related devices can be pooled."}, "kind": "container", "mandatory": true, "name": "session-pool", "qname": "ncs:session-pool", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "Control settings for no-overwrite sync check"}, "kind": "container", "mandatory": true, "name": "no-overwrite", "qname": "ncs:no-overwrite", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "Specifies the behaviour of a commit operation involving a\ndevice that is out of sync with NCS. Value accept assumes that\nthe device's sync state is unknown and it is cleared on commit.\nThe default behaviour is to reject such commits."}, "kind": "leaf", "name": "out-of-sync-commit-behaviour", "qname": "ncs:out-of-sync-commit-behaviour", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t40"}}, {"default": "use-lsa", "kind": "choice", "cases": [{"kind": "case", "name": "use-lsa", "children": [{"info": {"string": "Handle the LSA nodes as such. This is the default"}, "kind": "leaf", "name": "use-lsa", "qname": "ncs:use-lsa", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"primitive": true, "name": "empty"}}]}, {"kind": "case", "name": "no-lsa", "children": [{"info": {"string": "Do not handle any of the LSA nodes as such. These nodes\nwill be handled as any other device. This has the same\nresult as adding the commit flag 'no-lsa' to every commit."}, "kind": "leaf", "name": "no-lsa", "qname": "ncs:no-lsa", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"primitive": true, "name": "empty"}}]}], "name": "choice-lsa"}, {"info": {"string": "Show all active settings for the device"}, "kind": "container", "mandatory": true, "name": "active-settings", "qname": "ncs:active-settings", "is_config_false_callpoint": true, "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"info": {"string": "Additional protocols for the live-tree (read-only)"}, "kind": "list", "leafref_groups": [["authgroup"]], "min_elements": 0, "name": "live-status-protocol", "max_elements": "unbounded", "qname": "ncs:live-status-protocol", "children": [{"kind": "key", "mandatory": true, "name": "name", "qname": "ncs:name", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "string"}}, {"info": {"string": "IP Address for the management interface"}, "kind": "leaf", "name": "address", "qname": "ncs:address", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"namespace": "urn:ietf:params:xml:ns:yang:ietf-inet-types", "name": "host"}}, {"info": {"string": "Port for the management interface"}, "kind": "leaf", "name": "port", "qname": "ncs:port", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"namespace": "urn:ietf:params:xml:ns:yang:ietf-inet-types", "name": "port-number"}}, {"info": {"string": "SSH host key configuration"}, "kind": "container", "name": "ssh", "presence": true, "qname": "ncs:ssh", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}}, {"info": {"string": "Authentication credentials for the device"}, "kind": "leaf", "name": "authgroup", "type": {"primitive": true, "name": "string"}, "qname": "ncs:authgroup", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "leafref_target": "/ncs:devices/authgroups/group/name", "is_leafref": true}, {"info": {"string": "Management protocol for the device"}, "kind": "container", "mandatory": true, "name": "device-type", "qname": "ncs:device-type", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "Operational State for the live protocol"}, "kind": "container", "mandatory": true, "name": "state", "qname": "ncs:state", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"info": {"string": "List of capabillities supported by the device"}, "kind": "list", "min_elements": 0, "name": "capability", "max_elements": "unbounded", "qname": "ncs:capability", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "key": ["uri"], "mandatory": true, "config": false, "children": [{"info": {"string": "Capability URI"}, "kind": "key", "mandatory": true, "name": "uri", "type": {"primitive": true, "name": "string"}, "qname": "ncs:uri", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"info": {"string": "Capability revision"}, "kind": "leaf", "name": "revision", "type": {"primitive": true, "name": "string"}, "qname": "ncs:revision", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "config": false}, {"info": {"string": "Capability module"}, "kind": "leaf", "name": "module", "type": {"primitive": true, "name": "string"}, "qname": "ncs:module", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "config": false}, {"info": {"string": "Capability features"}, "kind": "leaf-list", "name": "feature", "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t83"}, "qname": "ncs:feature", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "config": false}, {"info": {"string": "Capability deviations"}, "kind": "leaf-list", "name": "deviation", "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t85"}, "qname": "ncs:deviation", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "config": false}]}], "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "key": ["name"], "mandatory": true, "leafrefGroups": [["authgroup"]]}, {"info": {"string": "Show states for the device"}, "kind": "container", "mandatory": true, "name": "state", "qname": "ncs:state", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "How the device was added to NCS"}, "kind": "container", "mandatory": true, "name": "source", "qname": "ncs:source", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "A list of capabilities supported by the device"}, "kind": "list", "min_elements": 0, "name": "capability", "max_elements": "unbounded", "qname": "ncs:capability", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "key": ["uri"], "mandatory": true, "config": false, "children": [{"kind": "key", "mandatory": true, "name": "uri", "type": {"primitive": true, "name": "string"}, "qname": "ncs:uri", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"kind": "leaf", "name": "revision", "config": false, "qname": "ncs:revision", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "type": {"primitive": true, "name": "string"}}, {"kind": "leaf", "name": "module", "config": false, "qname": "ncs:module", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "type": {"primitive": true, "name": "string"}}, {"kind": "leaf-list", "name": "feature", "config": false, "qname": "ncs:feature", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t43"}}, {"kind": "leaf-list", "name": "deviation", "config": false, "qname": "ncs:deviation", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t45"}}, {"info": {"string": "This action removes a capability from the list of capabilities.\nIf leaf module is set then corresponding module is attempted to\nbe removed from the list of modules for this device. This action\nis only intended to be used for pre-provisioning: it is not\npossible to override capabilities and modules provided by the\nNED implementation using this action."}, "kind": "action", "mandatory": true, "name": "remove", "qname": "ncs:remove", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}]}, {"info": {"string": "This is a list of the YANG modules supported by the device.\n\nThis list is populated the first time NCS connects to the\ndevice."}, "kind": "list", "min_elements": 0, "name": "module", "max_elements": "unbounded", "qname": "ncs:module", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "key": ["name"], "mandatory": true, "config": false, "children": [{"kind": "key", "mandatory": true, "name": "name", "type": {"primitive": true, "name": "string"}, "qname": "ncs:name", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"kind": "leaf", "name": "revision", "config": false, "qname": "ncs:revision", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "type": {"primitive": true, "name": "string"}}, {"kind": "leaf-list", "name": "feature", "config": false, "qname": "ncs:feature", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t47"}}, {"kind": "leaf-list", "name": "deviation", "config": false, "qname": "ncs:deviation", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t49"}}]}, {"info": {"string": "Contains vendor-specific information for\nidentifying the system platform.\n\nNEDs MAY augment this container with more device-specific\nnodes."}, "kind": "container", "mandatory": true, "name": "platform", "qname": "ncs:platform", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"info": {"string": "NCS copy of the device configuration"}, "kind": "container", "mandatory": true, "name": "config", "qname": "ncs:config", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "Status data fetched from the device"}, "kind": "container", "mandatory": true, "name": "live-status", "qname": "ncs:live-status", "is_config_false_callpoint": true, "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"info": {"string": "RPCs from the device"}, "kind": "container", "mandatory": true, "name": "rpc", "qname": "ncs:rpc", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "NETCONF notifications from the device"}, "kind": "container", "mandatory": true, "name": "netconf-notifications", "qname": "ncs:netconf-notifications", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "Show services that use this device"}, "kind": "leaf-list", "name": "service-list", "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t101"}, "qname": "ncs:service-list", "is_config_false_callpoint": true, "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "config": false}, {"info": {"string": "Notification address if different from device address"}, "kind": "leaf", "name": "snmp-notification-address", "qname": "ncs:snmp-notification-address", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"namespace": "urn:ietf:params:xml:ns:yang:ietf-inet-types", "name": "host"}}, {"info": {"string": "Device specific information"}, "kind": "container", "name": "platform", "presence": true, "when_targets": ["/ncs:devices/device/device-type/cli/ned-id"], "qname": "alu-meta:platform", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}}, {"info": {"string": "A summary of all active alarms per device."}, "kind": "container", "mandatory": true, "name": "alarm-summary", "qname": "al:alarm-summary", "is_config_false_callpoint": true, "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"info": {"string": "Note: this action overwrites existing list of capabilities.\n\nThis action copies the list of capabilities and the list of modules\nfrom another device or profile. When used on a device, this action\nis only intended to be used for pre-provisioning: it is not possible\nto override capabilities and modules provided by the\nNED implementation using this action."}, "kind": "action", "mandatory": true, "name": "copy-capabilities", "qname": "ncs:copy-capabilities", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Note: this action overwrites existing list of capabilities.\n\nThis action populates the list of capabilities based on the\nconfigured ned-id for this device, if possible. NCS will look up\nthe package corresponding to the ned-id and add all the modules\nfrom this packages to the list of this device's capabilities and\nlist of modules. It is the responsibility of the caller to verify\nthat the automatically populated list of capabilities matches actual\ndevice's capabilities. The list of capabilities can then be\nfine-tuned using add-capability and capability/remove actions.\nCurrently this approach will only work for CLI and generic devices.\nThis action is only intended to be used for pre-provisioning:\nit is not possible to override capabilities and modules provided\nby the NED implementation using this action."}, "kind": "action", "mandatory": true, "name": "find-capabilities", "qname": "ncs:find-capabilities", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "This action adds a capability to the list of capabilities.\nIf uri is specified, then it is parsed as YANG capability string\nand module, revision, feature and deviation parameters are derived\nfrom the string. If module is specified, then the namespace is\nlooked up in the list of loaded namespaces and capability string\nconstructed automatically. If the module is specified and the\nattempt to look it up failed, then the action does nothing.\nIf module is specified or can be derived from capability string,\nthen the module is also added/replaced in the list of modules. This\naction is only intended to be used for pre-provisioning: it is not\npossible to override capabilities and modules provided by the NED\nimplementation using this action."}, "kind": "action", "mandatory": true, "name": "add-capability", "qname": "ncs:add-capability", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Take a named template and copy it here"}, "kind": "action", "mandatory": true, "name": "apply-template", "leafrefGroups": [["template-name"]], "qname": "ncs:apply-template", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}, "leafref_groups": [["template-name"]]}, {"info": {"string": "Instantiate the config for the device from existing device"}, "kind": "action", "mandatory": true, "name": "instantiate-from-other-device", "leafrefGroups": [["device-name"]], "qname": "ncs:instantiate-from-other-device", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}, "leafref_groups": [["device-name"]]}, {"info": {"string": "Compare the actual device config with the NCS copy"}, "kind": "action", "mandatory": true, "name": "compare-config", "qname": "ncs:compare-config", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Synchronize the config by pulling from the device"}, "kind": "action", "mandatory": true, "name": "sync-from", "qname": "ncs:sync-from", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Synchronize the config by pushing to the device"}, "kind": "action", "mandatory": true, "name": "sync-to", "qname": "ncs:sync-to", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Check if the NCS config is in sync with the device"}, "kind": "action", "mandatory": true, "name": "check-sync", "qname": "ncs:check-sync", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Check if NCS and the device have compatible YANG modules"}, "kind": "action", "mandatory": true, "name": "check-yang-modules", "qname": "ncs:check-yang-modules", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Connect to the device"}, "kind": "action", "mandatory": true, "name": "connect", "qname": "ncs:connect", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Close all sessions to the device"}, "kind": "action", "mandatory": true, "name": "disconnect", "qname": "ncs:disconnect", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "ICMP ping the device"}, "kind": "action", "mandatory": true, "name": "ping", "qname": "ncs:ping", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Delete the config in NCS without deleting it in the device"}, "kind": "action", "mandatory": true, "name": "delete-config", "qname": "ncs:delete-config", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Secure copy file to the device"}, "kind": "action", "mandatory": true, "name": "scp-to", "qname": "ncs:scp-to", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Secure copy file to the device"}, "kind": "action", "mandatory": true, "name": "scp-from", "qname": "ncs:scp-from", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}], "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "key": ["name"], "min_elements": 0, "leafrefGroups": [["remote-node"], ["authgroup"], ["device-profile"]]}} diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/devices_schema.json b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/devices_schema.json new file mode 100644 index 00000000..541ba010 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/devices_schema.json @@ -0,0 +1 @@ +{"meta": {"prefix": "ncs", "namespace": "http://tail-f.com/ns/ncs", "types": {"http://tail-f.com/ns/ncs:t68": [{"list_type": [{"leaf-list": true, "name": "http://tail-f.com/ns/ncs:t68"}], "leaf_type": [{"name": "string"}]}], "http://tail-f.com/ns/ncs:t85": [{"list_type": [{"leaf-list": true, "name": "http://tail-f.com/ns/ncs:t85"}], "leaf_type": [{"name": "string"}]}], "http://tail-f.com/ns/ncs:t83": [{"list_type": [{"leaf-list": true, "name": "http://tail-f.com/ns/ncs:t83"}], "leaf_type": [{"name": "string"}]}], "http://tail-f.com/ns/ncs:t60": [{"list_type": [{"leaf-list": true, "name": "http://tail-f.com/ns/ncs:t60"}], "leaf_type": [{"name": "string"}]}], "http://tail-f.com/ns/ncs:t101": [{"list_type": [{"leaf-list": true, "name": "http://tail-f.com/ns/ncs:t101"}], "leaf_type": [{"name": "string"}]}], "urn:ietf:params:xml:ns:yang:ietf-inet-types:host": [{"union": [[{"name": "urn:ietf:params:xml:ns:yang:ietf-inet-types:ip-address"}, {"name": "ip-address"}], [{"max-length": {"value": 253}, "min-length": {"value": 1}, "name": "urn:ietf:params:xml:ns:yang:ietf-inet-types:domain-name", "pattern": {"value": "((([a-zA-Z0-9_]([a-zA-Z0-9\\-_]){0,61})?[a-zA-Z0-9]\\.)*([a-zA-Z0-9_]([a-zA-Z0-9\\-_]){0,61})?[a-zA-Z0-9]\\.?)|\\."}}, {"name": "string"}]]}], "http://tail-f.com/ns/ncs:trace-flag": [{"name": "http://tail-f.com/ns/ncs:trace-flag", "enumeration": [{"info": "Trace is disabled", "label": "false"}, {"info": "Raw, unformatted data", "label": "raw"}, {"info": "Pretty-printed data", "label": "pretty"}]}, {"name": "string"}], "http://tail-f.com/ns/ncs:t43": [{"list_type": [{"leaf-list": true, "name": "http://tail-f.com/ns/ncs:t43"}], "leaf_type": [{"name": "string"}]}], "http://tail-f.com/ns/ncs:t27": [{"range": {"value": [["1", "4294967"]]}, "name": "http://tail-f.com/ns/ncs:t27"}, {"name": "uint32"}], "http://tail-f.com/ns/ncs:t40": [{"name": "http://tail-f.com/ns/ncs:t40", "enumeration": [{"label": "reject"}, {"label": "accept"}]}, {"name": "string"}], "http://tail-f.com/ns/ncs:t47": [{"list_type": [{"leaf-list": true, "name": "http://tail-f.com/ns/ncs:t47"}], "leaf_type": [{"name": "string"}]}], "http://tail-f.com/ns/ncs:t45": [{"list_type": [{"leaf-list": true, "name": "http://tail-f.com/ns/ncs:t45"}], "leaf_type": [{"name": "string"}]}], "http://tail-f.com/ns/ncs:t49": [{"list_type": [{"leaf-list": true, "name": "http://tail-f.com/ns/ncs:t49"}], "leaf_type": [{"name": "string"}]}], "http://tail-f.com/ns/ncs:t29": [{"range": {"value": [["1", "4294967"]]}, "name": "http://tail-f.com/ns/ncs:t29"}, {"name": "uint32"}], "http://tail-f.com/ns/ncs:t28": [{"range": {"value": [["1", "4294967"]]}, "name": "http://tail-f.com/ns/ncs:t28"}, {"name": "uint32"}], "http://tail-f.com/ns/ncs:node-name": [{"name": "http://tail-f.com/ns/ncs:node-name"}, {"max-length": {"value": 253}, "min-length": {"value": 1}, "name": "urn:ietf:params:xml:ns:yang:ietf-inet-types:domain-name", "pattern": {"value": "((([a-zA-Z0-9_]([a-zA-Z0-9\\-_]){0,61})?[a-zA-Z0-9]\\.)*([a-zA-Z0-9_]([a-zA-Z0-9\\-_]){0,61})?[a-zA-Z0-9]\\.?)|\\."}}, {"name": "string"}], "http://tail-f.com/ns/ncs:t74": [{"list_type": [{"leaf-list": true, "name": "http://tail-f.com/ns/ncs:t74"}], "leaf_type": [{"name": "string"}]}], "http://tail-f.com/ns/ncs:t72": [{"list_type": [{"leaf-list": true, "name": "http://tail-f.com/ns/ncs:t72"}], "leaf_type": [{"name": "string"}]}], "http://tail-f.com/ns/ncs:t70": [{"list_type": [{"leaf-list": true, "name": "http://tail-f.com/ns/ncs:t70"}], "leaf_type": [{"name": "string"}]}], "urn:ietf:params:xml:ns:yang:ietf-inet-types:port-number": [{"range": {"value": [["0", "65535"]]}, "name": "urn:ietf:params:xml:ns:yang:ietf-inet-types:port-number"}, {"name": "uint16"}], "http://tail-f.com/ns/ncs:t56": [{"list_type": [{"leaf-list": true, "name": "http://tail-f.com/ns/ncs:t56"}], "leaf_type": [{"name": "string"}]}], "http://tail-f.com/ns/ncs:t58": [{"list_type": [{"leaf-list": true, "name": "http://tail-f.com/ns/ncs:t58"}], "leaf_type": [{"name": "string"}]}]}, "keypath": "/ncs:devices"}, "data": {"info": {"string": "The managed devices and device communication settings"}, "kind": "container", "mandatory": true, "name": "devices", "contains_when_statement": true, "qname": "ncs:devices", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "children": [{"info": {"string": "Global settings for all managed devices."}, "kind": "container", "mandatory": true, "name": "global-settings", "qname": "ncs:global-settings", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "Device profile parameters"}, "kind": "container", "mandatory": true, "name": "profiles", "qname": "ncs:profiles", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "Authentication for managed devices"}, "kind": "container", "mandatory": true, "name": "authgroups", "qname": "ncs:authgroups", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "Named configuration templates for devices"}, "kind": "list", "min_elements": 0, "name": "template", "max_elements": "unbounded", "qname": "ncs:template", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "key": ["name"], "mandatory": true, "children": [{"info": {"string": "The name of a specific template configuration."}, "kind": "key", "mandatory": true, "name": "name", "qname": "ncs:name", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "string"}}, {"info": {"string": "This container is augmented with data models from the devices."}, "kind": "container", "mandatory": true, "name": "config", "qname": "ncs:config", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}]}, {"info": {"string": "Groups of devices"}, "kind": "list", "leafref_groups": [["device-name"], ["device-group"], ["member"]], "min_elements": 0, "name": "device-group", "max_elements": "unbounded", "qname": "ncs:device-group", "children": [{"kind": "key", "mandatory": true, "name": "name", "qname": "ncs:name", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "string"}}, {"info": {"string": "Physical location of devices in the group"}, "kind": "container", "mandatory": true, "name": "location", "qname": "ncs:location", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "Device within group"}, "kind": "leaf-list", "name": "device-name", "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t56"}, "qname": "ncs:device-name", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "leafref_target": "/ncs:devices/device/name", "is_leafref": true}, {"info": {"string": "Group within group"}, "kind": "leaf-list", "name": "device-group", "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t58"}, "qname": "ncs:device-group", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "leafref_target": "/ncs:devices/device-group/name", "is_leafref": true}, {"info": {"string": "Flattened list of all members"}, "kind": "leaf-list", "name": "member", "is_leafref": true, "qname": "ncs:member", "is_config_false_callpoint": true, "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "leafref_target": "/ncs:devices/device/name", "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t60"}, "config": false}, {"info": {"string": "RPCs from the device's"}, "kind": "container", "mandatory": true, "name": "rpc", "qname": "ncs:rpc", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "A summary of all active alarms per device group."}, "kind": "container", "mandatory": true, "name": "alarm-summary", "qname": "al:alarm-summary", "is_config_false_callpoint": true, "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"info": {"string": "Set up sessions to all unlocked devices"}, "kind": "action", "mandatory": true, "name": "connect", "qname": "ncs:connect", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Synchronize the config by pushing to the devices"}, "kind": "action", "mandatory": true, "name": "sync-to", "qname": "ncs:sync-to", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Synchronize the config by pulling from the devices"}, "kind": "action", "mandatory": true, "name": "sync-from", "qname": "ncs:sync-from", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Check if the NCS config is in sync with the device"}, "kind": "action", "mandatory": true, "name": "check-sync", "qname": "ncs:check-sync", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Check if NCS and the devices have compatible YANG modules"}, "kind": "action", "mandatory": true, "name": "check-yang-modules", "qname": "ncs:check-yang-modules", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Retrieve SSH host keys from all devices"}, "kind": "action", "mandatory": true, "name": "fetch-ssh-host-keys", "qname": "ncs:fetch-ssh-host-keys", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Take a named template and copy it here"}, "kind": "action", "mandatory": true, "name": "apply-template", "leafrefGroups": [["template-name"]], "qname": "ncs:apply-template", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}, "leafref_groups": [["template-name"]]}], "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "key": ["name"], "mandatory": true, "leafrefGroups": [["device-name"], ["device-group"], ["member"]]}, {"info": {"string": "A list of named groups of MIBs"}, "kind": "list", "leafref_groups": [["mib-group"]], "min_elements": 0, "name": "mib-group", "max_elements": "unbounded", "qname": "ncs:mib-group", "children": [{"info": {"string": "An arbitrary name of the MIB group."}, "kind": "key", "mandatory": true, "name": "name", "qname": "ncs:name", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "string"}}, {"info": {"string": "MIB module names or name prefixes"}, "kind": "leaf-list", "name": "mib-module", "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t68"}, "qname": "ncs:mib-module", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "leafref_target": "/ncs:devices/device-module/mib-module", "is_leafref": true}, {"info": {"string": "A list of MIB groups contained in this MIB group"}, "kind": "leaf-list", "name": "mib-group", "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t70"}, "qname": "ncs:mib-group", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "leafref_target": "/ncs:devices/mib-group/name", "is_leafref": true}], "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "key": ["name"], "mandatory": true, "leafrefGroups": [["mib-group"]]}, {"info": {"string": "List the devices and supported modules"}, "kind": "list", "min_elements": 0, "name": "device-module", "max_elements": "unbounded", "qname": "ncs:device-module", "is_config_false_callpoint": true, "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "key": ["name"], "mandatory": true, "config": false, "children": [{"info": {"string": "The module name"}, "kind": "key", "mandatory": true, "name": "name", "type": {"primitive": true, "name": "string"}, "qname": "ncs:name", "is_config_false_callpoint": true, "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"info": {"string": "The module revision"}, "kind": "leaf-list", "name": "revision", "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t72"}, "qname": "ncs:revision", "is_config_false_callpoint": true, "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "config": false}, {"info": {"string": "The XML namespace uri for the module"}, "kind": "leaf", "name": "uri", "type": {"primitive": true, "name": "string"}, "qname": "ncs:uri", "is_config_false_callpoint": true, "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "config": false}, {"info": {"string": "The names of the devices that support this module"}, "kind": "leaf-list", "name": "devices", "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t74"}, "qname": "ncs:devices", "is_config_false_callpoint": true, "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "config": false}]}, {"info": {"string": "The list of managed devices"}, "kind": "list", "leafref_groups": [["remote-node"], ["authgroup"], ["device-profile"]], "min_elements": 0, "name": "device", "max_elements": "unbounded", "qname": "ncs:device", "children": [{"info": {"string": "A string uniquely identifying the managed device"}, "kind": "key", "mandatory": true, "name": "name", "qname": "ncs:name", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "string"}}, {"info": {"string": "IP address or host name for the management interface"}, "kind": "leaf", "name": "address", "qname": "ncs:address", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"namespace": "urn:ietf:params:xml:ns:yang:ietf-inet-types", "name": "host"}}, {"info": {"string": "Port for the management interface"}, "kind": "leaf", "name": "port", "qname": "ncs:port", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"namespace": "urn:ietf:params:xml:ns:yang:ietf-inet-types", "name": "port-number"}}, {"info": {"string": "Name of remote node which connects to device"}, "kind": "leaf", "name": "remote-node", "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "node-name"}, "qname": "ncs:remote-node", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "leafref_target": "/ncs:cluster/remote-node/name", "is_leafref": true}, {"info": {"string": "SSH connection configuration"}, "kind": "container", "mandatory": true, "name": "ssh", "qname": "ncs:ssh", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "Free form textual description"}, "kind": "leaf", "name": "description", "qname": "ncs:description", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"primitive": true, "name": "string"}}, {"info": {"string": "Physical location of devices in the group"}, "kind": "container", "mandatory": true, "name": "location", "qname": "ncs:location", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "Authentication credentials for the device"}, "kind": "leaf", "name": "authgroup", "type": {"primitive": true, "name": "string"}, "qname": "ncs:authgroup", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "leafref_target": "/ncs:devices/authgroups/group/name", "is_leafref": true}, {"info": {"string": "Management protocol for the device"}, "kind": "container", "mandatory": true, "name": "device-type", "qname": "ncs:device-type", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"kind": "leaf", "name": "device-profile", "type": {"primitive": true, "name": "string"}, "qname": "ncs:device-profile", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "leafref_target": "/ncs:devices/profiles/profile/name", "is_leafref": true}, {"info": {"string": "Timeout in seconds for new connections"}, "kind": "leaf", "name": "connect-timeout", "qname": "ncs:connect-timeout", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "units": "seconds", "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t27"}}, {"info": {"string": "Timeout in seconds used when reading data"}, "kind": "leaf", "name": "read-timeout", "qname": "ncs:read-timeout", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "units": "seconds", "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t28"}}, {"info": {"string": "Timeout in seconds used when writing data"}, "kind": "leaf", "name": "write-timeout", "qname": "ncs:write-timeout", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "units": "seconds", "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t29"}}, {"info": {"string": "Controls SSH keep alive settings"}, "kind": "container", "mandatory": true, "name": "ssh-keep-alive", "qname": "ncs:ssh-keep-alive", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "Trace the southbound communication to devices"}, "kind": "leaf", "name": "trace", "qname": "ncs:trace", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "trace-flag"}}, {"info": {"string": "Control which device capabilities NCS uses"}, "kind": "container", "mandatory": true, "name": "ned-settings", "qname": "ncs:ned-settings", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "Control settings for the commit-queue"}, "kind": "container", "mandatory": true, "name": "commit-queue", "qname": "ncs:commit-queue", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "Control how sessions to related devices can be pooled."}, "kind": "container", "mandatory": true, "name": "session-pool", "qname": "ncs:session-pool", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "Control settings for no-overwrite sync check"}, "kind": "container", "mandatory": true, "name": "no-overwrite", "qname": "ncs:no-overwrite", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "Specifies the behaviour of a commit operation involving a\ndevice that is out of sync with NCS. Value accept assumes that\nthe device's sync state is unknown and it is cleared on commit.\nThe default behaviour is to reject such commits."}, "kind": "leaf", "name": "out-of-sync-commit-behaviour", "qname": "ncs:out-of-sync-commit-behaviour", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t40"}}, {"default": "use-lsa", "kind": "choice", "cases": [{"kind": "case", "name": "use-lsa", "children": [{"info": {"string": "Handle the LSA nodes as such. This is the default"}, "kind": "leaf", "name": "use-lsa", "qname": "ncs:use-lsa", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"primitive": true, "name": "empty"}}]}, {"kind": "case", "name": "no-lsa", "children": [{"info": {"string": "Do not handle any of the LSA nodes as such. These nodes\nwill be handled as any other device. This has the same\nresult as adding the commit flag 'no-lsa' to every commit."}, "kind": "leaf", "name": "no-lsa", "qname": "ncs:no-lsa", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"primitive": true, "name": "empty"}}]}], "name": "choice-lsa"}, {"info": {"string": "Show all active settings for the device"}, "kind": "container", "mandatory": true, "name": "active-settings", "qname": "ncs:active-settings", "is_config_false_callpoint": true, "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"info": {"string": "Additional protocols for the live-tree (read-only)"}, "kind": "list", "leafref_groups": [["authgroup"]], "min_elements": 0, "name": "live-status-protocol", "max_elements": "unbounded", "qname": "ncs:live-status-protocol", "children": [{"kind": "key", "mandatory": true, "name": "name", "qname": "ncs:name", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "string"}}, {"info": {"string": "IP Address for the management interface"}, "kind": "leaf", "name": "address", "qname": "ncs:address", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"namespace": "urn:ietf:params:xml:ns:yang:ietf-inet-types", "name": "host"}}, {"info": {"string": "Port for the management interface"}, "kind": "leaf", "name": "port", "qname": "ncs:port", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"namespace": "urn:ietf:params:xml:ns:yang:ietf-inet-types", "name": "port-number"}}, {"info": {"string": "SSH host key configuration"}, "kind": "container", "name": "ssh", "presence": true, "qname": "ncs:ssh", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}}, {"info": {"string": "Authentication credentials for the device"}, "kind": "leaf", "name": "authgroup", "type": {"primitive": true, "name": "string"}, "qname": "ncs:authgroup", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "leafref_target": "/ncs:devices/authgroups/group/name", "is_leafref": true}, {"info": {"string": "Management protocol for the device"}, "kind": "container", "mandatory": true, "name": "device-type", "qname": "ncs:device-type", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "Operational State for the live protocol"}, "kind": "container", "mandatory": true, "name": "state", "qname": "ncs:state", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"info": {"string": "List of capabillities supported by the device"}, "kind": "list", "min_elements": 0, "name": "capability", "max_elements": "unbounded", "qname": "ncs:capability", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "key": ["uri"], "mandatory": true, "config": false, "children": [{"info": {"string": "Capability URI"}, "kind": "key", "mandatory": true, "name": "uri", "type": {"primitive": true, "name": "string"}, "qname": "ncs:uri", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"info": {"string": "Capability revision"}, "kind": "leaf", "name": "revision", "type": {"primitive": true, "name": "string"}, "qname": "ncs:revision", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "config": false}, {"info": {"string": "Capability module"}, "kind": "leaf", "name": "module", "type": {"primitive": true, "name": "string"}, "qname": "ncs:module", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "config": false}, {"info": {"string": "Capability features"}, "kind": "leaf-list", "name": "feature", "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t83"}, "qname": "ncs:feature", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "config": false}, {"info": {"string": "Capability deviations"}, "kind": "leaf-list", "name": "deviation", "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t85"}, "qname": "ncs:deviation", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "config": false}]}], "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "key": ["name"], "mandatory": true, "leafrefGroups": [["authgroup"]]}, {"info": {"string": "Show states for the device"}, "kind": "container", "mandatory": true, "name": "state", "qname": "ncs:state", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "How the device was added to NCS"}, "kind": "container", "mandatory": true, "name": "source", "qname": "ncs:source", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "A list of capabilities supported by the device"}, "kind": "list", "min_elements": 0, "name": "capability", "max_elements": "unbounded", "qname": "ncs:capability", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "key": ["uri"], "mandatory": true, "config": false, "children": [{"kind": "key", "mandatory": true, "name": "uri", "type": {"primitive": true, "name": "string"}, "qname": "ncs:uri", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"kind": "leaf", "name": "revision", "config": false, "qname": "ncs:revision", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "type": {"primitive": true, "name": "string"}}, {"kind": "leaf", "name": "module", "config": false, "qname": "ncs:module", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "type": {"primitive": true, "name": "string"}}, {"kind": "leaf-list", "name": "feature", "config": false, "qname": "ncs:feature", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t43"}}, {"kind": "leaf-list", "name": "deviation", "config": false, "qname": "ncs:deviation", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t45"}}, {"info": {"string": "This action removes a capability from the list of capabilities.\nIf leaf module is set then corresponding module is attempted to\nbe removed from the list of modules for this device. This action\nis only intended to be used for pre-provisioning: it is not\npossible to override capabilities and modules provided by the\nNED implementation using this action."}, "kind": "action", "mandatory": true, "name": "remove", "qname": "ncs:remove", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}]}, {"info": {"string": "This is a list of the YANG modules supported by the device.\n\nThis list is populated the first time NCS connects to the\ndevice."}, "kind": "list", "min_elements": 0, "name": "module", "max_elements": "unbounded", "qname": "ncs:module", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "key": ["name"], "mandatory": true, "config": false, "children": [{"kind": "key", "mandatory": true, "name": "name", "type": {"primitive": true, "name": "string"}, "qname": "ncs:name", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"kind": "leaf", "name": "revision", "config": false, "qname": "ncs:revision", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "type": {"primitive": true, "name": "string"}}, {"kind": "leaf-list", "name": "feature", "config": false, "qname": "ncs:feature", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t47"}}, {"kind": "leaf-list", "name": "deviation", "config": false, "qname": "ncs:deviation", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t49"}}]}, {"info": {"string": "Contains vendor-specific information for\nidentifying the system platform.\n\nNEDs MAY augment this container with more device-specific\nnodes."}, "kind": "container", "mandatory": true, "name": "platform", "qname": "ncs:platform", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"info": {"string": "NCS copy of the device configuration"}, "kind": "container", "mandatory": true, "name": "config", "qname": "ncs:config", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "Status data fetched from the device"}, "kind": "container", "mandatory": true, "name": "live-status", "qname": "ncs:live-status", "is_config_false_callpoint": true, "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"info": {"string": "RPCs from the device"}, "kind": "container", "mandatory": true, "name": "rpc", "qname": "ncs:rpc", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "NETCONF notifications from the device"}, "kind": "container", "mandatory": true, "name": "netconf-notifications", "qname": "ncs:netconf-notifications", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "Show services that use this device"}, "kind": "leaf-list", "name": "service-list", "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t101"}, "qname": "ncs:service-list", "is_config_false_callpoint": true, "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "config": false}, {"info": {"string": "Notification address if different from device address"}, "kind": "leaf", "name": "snmp-notification-address", "qname": "ncs:snmp-notification-address", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"namespace": "urn:ietf:params:xml:ns:yang:ietf-inet-types", "name": "host"}}, {"info": {"string": "Device specific information"}, "kind": "container", "name": "platform", "presence": true, "when_targets": ["/ncs:devices/device/device-type/cli/ned-id"], "qname": "alu-meta:platform", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}}, {"info": {"string": "A summary of all active alarms per device."}, "kind": "container", "mandatory": true, "name": "alarm-summary", "qname": "al:alarm-summary", "is_config_false_callpoint": true, "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"info": {"string": "Note: this action overwrites existing list of capabilities.\n\nThis action copies the list of capabilities and the list of modules\nfrom another device or profile. When used on a device, this action\nis only intended to be used for pre-provisioning: it is not possible\nto override capabilities and modules provided by the\nNED implementation using this action."}, "kind": "action", "mandatory": true, "name": "copy-capabilities", "qname": "ncs:copy-capabilities", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Note: this action overwrites existing list of capabilities.\n\nThis action populates the list of capabilities based on the\nconfigured ned-id for this device, if possible. NCS will look up\nthe package corresponding to the ned-id and add all the modules\nfrom this packages to the list of this device's capabilities and\nlist of modules. It is the responsibility of the caller to verify\nthat the automatically populated list of capabilities matches actual\ndevice's capabilities. The list of capabilities can then be\nfine-tuned using add-capability and capability/remove actions.\nCurrently this approach will only work for CLI and generic devices.\nThis action is only intended to be used for pre-provisioning:\nit is not possible to override capabilities and modules provided\nby the NED implementation using this action."}, "kind": "action", "mandatory": true, "name": "find-capabilities", "qname": "ncs:find-capabilities", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "This action adds a capability to the list of capabilities.\nIf uri is specified, then it is parsed as YANG capability string\nand module, revision, feature and deviation parameters are derived\nfrom the string. If module is specified, then the namespace is\nlooked up in the list of loaded namespaces and capability string\nconstructed automatically. If the module is specified and the\nattempt to look it up failed, then the action does nothing.\nIf module is specified or can be derived from capability string,\nthen the module is also added/replaced in the list of modules. This\naction is only intended to be used for pre-provisioning: it is not\npossible to override capabilities and modules provided by the NED\nimplementation using this action."}, "kind": "action", "mandatory": true, "name": "add-capability", "qname": "ncs:add-capability", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Take a named template and copy it here"}, "kind": "action", "mandatory": true, "name": "apply-template", "leafrefGroups": [["template-name"]], "qname": "ncs:apply-template", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}, "leafref_groups": [["template-name"]]}, {"info": {"string": "Instantiate the config for the device from existing device"}, "kind": "action", "mandatory": true, "name": "instantiate-from-other-device", "leafrefGroups": [["device-name"]], "qname": "ncs:instantiate-from-other-device", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}, "leafref_groups": [["device-name"]]}, {"info": {"string": "Compare the actual device config with the NCS copy"}, "kind": "action", "mandatory": true, "name": "compare-config", "qname": "ncs:compare-config", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Synchronize the config by pulling from the device"}, "kind": "action", "mandatory": true, "name": "sync-from", "qname": "ncs:sync-from", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Synchronize the config by pushing to the device"}, "kind": "action", "mandatory": true, "name": "sync-to", "qname": "ncs:sync-to", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Check if the NCS config is in sync with the device"}, "kind": "action", "mandatory": true, "name": "check-sync", "qname": "ncs:check-sync", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Check if NCS and the device have compatible YANG modules"}, "kind": "action", "mandatory": true, "name": "check-yang-modules", "qname": "ncs:check-yang-modules", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Connect to the device"}, "kind": "action", "mandatory": true, "name": "connect", "qname": "ncs:connect", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Close all sessions to the device"}, "kind": "action", "mandatory": true, "name": "disconnect", "qname": "ncs:disconnect", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "ICMP ping the device"}, "kind": "action", "mandatory": true, "name": "ping", "qname": "ncs:ping", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Delete the config in NCS without deleting it in the device"}, "kind": "action", "mandatory": true, "name": "delete-config", "qname": "ncs:delete-config", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Secure copy file to the device"}, "kind": "action", "mandatory": true, "name": "scp-to", "qname": "ncs:scp-to", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Secure copy file to the device"}, "kind": "action", "mandatory": true, "name": "scp-from", "qname": "ncs:scp-from", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}], "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "key": ["name"], "mandatory": true, "leafrefGroups": [["remote-node"], ["authgroup"], ["device-profile"]]}, {"info": {"string": "List of queued and completed commits"}, "kind": "container", "mandatory": true, "name": "commit-queue", "qname": "ncs:commit-queue", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"info": {"string": "List of pooled NED sessions"}, "kind": "container", "mandatory": true, "name": "session-pool", "qname": "ncs:session-pool", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"info": {"string": "Set up sessions to all unlocked devices"}, "kind": "action", "mandatory": true, "name": "connect", "leafrefGroups": [["device"]], "qname": "ncs:connect", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}, "leafref_groups": [["device"]]}, {"info": {"string": "Synchronize the config by pushing to the devices"}, "kind": "action", "mandatory": true, "name": "sync-to", "leafrefGroups": [["device"]], "qname": "ncs:sync-to", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}, "leafref_groups": [["device"]]}, {"info": {"string": "Synchronize the config by pulling from the devices"}, "kind": "action", "mandatory": true, "name": "sync-from", "leafrefGroups": [["device"]], "qname": "ncs:sync-from", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}, "leafref_groups": [["device"]]}, {"info": {"string": "Close all sessions to all devices"}, "kind": "action", "mandatory": true, "name": "disconnect", "qname": "ncs:disconnect", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Check if the NCS config is in sync with the device"}, "kind": "action", "mandatory": true, "name": "check-sync", "leafrefGroups": [["device"]], "qname": "ncs:check-sync", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}, "leafref_groups": [["device"]]}, {"info": {"string": "Check if NCS and the devices have compatible YANG modules"}, "kind": "action", "mandatory": true, "name": "check-yang-modules", "leafrefGroups": [["device"]], "qname": "ncs:check-yang-modules", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}, "leafref_groups": [["device"]]}, {"info": {"string": "Retrieve SSH host keys from all devices"}, "kind": "action", "mandatory": true, "name": "fetch-ssh-host-keys", "leafrefGroups": [["device"]], "qname": "ncs:fetch-ssh-host-keys", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}, "leafref_groups": [["device"]]}, {"info": {"string": "Clear all trace files"}, "kind": "action", "mandatory": true, "name": "clear-trace", "qname": "ncs:clear-trace", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Synchronize parts of the devices' configuration by pulling from\nthe network."}, "kind": "action", "mandatory": true, "name": "partial-sync-from", "qname": "ncs:partial-sync-from", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}]}} diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/l3vpn_l3vpn_endpoint_schema.json b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/l3vpn_l3vpn_endpoint_schema.json new file mode 100644 index 00000000..0330aeb9 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/l3vpn_l3vpn_endpoint_schema.json @@ -0,0 +1 @@ +{"meta": {"prefix": "l3vpn", "namespace": "http://com/example/l3vpn", "types": {}, "keypath": "/l3vpn:vpn/l3vpn/endpoint"}, "data": {"kind": "list", "leafref_groups": [["ce-device"]], "min_elements": 0, "name": "endpoint", "max_elements": "unbounded", "qname": "l3vpn:endpoint", "children": [{"info": {"string": "Endpoint identifier"}, "kind": "key", "mandatory": true, "name": "id", "qname": "l3vpn:id", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "string"}}, {"kind": "leaf", "mandatory": true, "name": "ce-device", "type": {"primitive": true, "name": "string"}, "qname": "l3vpn:ce-device", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "leafref_target": "/ncs:devices/device/name", "is_leafref": true}, {"kind": "leaf", "mandatory": true, "name": "ce-interface", "qname": "l3vpn:ce-interface", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "string"}}, {"kind": "leaf", "mandatory": true, "name": "ip-network", "qname": "l3vpn:ip-network", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "ip-prefix"}}, {"info": {"string": "Bandwidth in bps"}, "kind": "leaf", "mandatory": true, "name": "bandwidth", "qname": "l3vpn:bandwidth", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "uint32"}}, {"info": {"string": "CE Router as-number"}, "kind": "leaf", "name": "as-number", "qname": "l3vpn:as-number", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"primitive": true, "name": "uint32"}}], "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "key": ["id"], "mandatory": true, "leafrefGroups": [["ce-device"]]}} diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/l3vpn_l3vpn_schema.json b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/l3vpn_l3vpn_schema.json new file mode 100644 index 00000000..2737e7a5 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/l3vpn_l3vpn_schema.json @@ -0,0 +1 @@ +{"meta": {"prefix": "l3vpn", "namespace": "http://com/example/l3vpn", "types": {"http://com/example/l3vpn:t19": [{"list_type": [{"leaf-list": true, "name": "http://com/example/l3vpn:t19"}], "leaf_type": [{"name": "instance-identifier"}]}], "urn:ietf:params:xml:ns:yang:ietf-inet-types:port-number": [{"range": {"value": [["0", "65535"]]}, "name": "urn:ietf:params:xml:ns:yang:ietf-inet-types:port-number"}, {"name": "uint16"}], "http://tail-f.com/ns/ncs:outformat-deep-check-sync": [{"name": "http://tail-f.com/ns/ncs:outformat-deep-check-sync", "enumeration": [{"info": "The CLI config that would have to be applied\nto the device(s) in order for the service to\nbecome in sync with the network.", "label": "cli"}, {"info": "The XML (NETCONF format) that would have to be\napplied to the device(s) in order for the service to\nbecome in sync with the network.", "label": "xml"}, {"info": "Returns if the service is in sync or not.", "label": "boolean"}]}, {"name": "string"}], "http://com/example/l3vpn:t21": [{"list_type": [{"leaf-list": true, "name": "http://com/example/l3vpn:t21"}], "leaf_type": [{"name": "string"}]}], "http://com/example/l3vpn:t15": [{"list_type": [{"leaf-list": true, "name": "http://com/example/l3vpn:t15"}], "leaf_type": [{"name": "string"}]}], "http://com/example/l3vpn:protocol-type": [{"name": "http://com/example/l3vpn:protocol-type", "enumeration": [{"label": "icmp"}, {"label": "igmp"}, {"label": "ipip"}, {"label": "tcp"}, {"label": "egp"}, {"label": "udp"}, {"label": "rsvp"}, {"label": "gre"}, {"label": "esp"}, {"label": "ah"}, {"label": "icmp6"}, {"label": "ospf"}, {"label": "pim"}, {"label": "sctp"}]}, {"name": "string"}], "http://com/example/l3vpn:t17": [{"list_type": [{"leaf-list": true, "name": "http://com/example/l3vpn:t17"}], "leaf_type": [{"name": "instance-identifier"}]}], "http://com/example/l3vpn:t23": [{"list_type": [{"leaf-list": true, "name": "http://com/example/l3vpn:t23"}], "leaf_type": [{"name": "string"}]}], "http://com/example/l3vpn:t11": [{"list_type": [{"leaf-list": true, "name": "http://com/example/l3vpn:t11"}], "leaf_type": [{"name": "instance-identifier"}]}], "http://com/example/l3vpn:t13": [{"list_type": [{"leaf-list": true, "name": "http://com/example/l3vpn:t13"}], "leaf_type": [{"name": "instance-identifier"}]}], "http://com/example/l3vpn:t24": [{"name": "http://com/example/l3vpn:t24", "enumeration": [{"label": "waiting"}, {"label": "executing"}, {"label": "blocking"}, {"label": "blocked"}, {"label": "failed"}, {"label": "admin-cleared"}, {"label": "commit-queue-failed"}]}, {"name": "string"}], "http://tail-f.com/ns/ncs:log-entry-t": [{"info": "This leaf identifies the specific log entry.", "name": "http://tail-f.com/ns/ncs:log-entry-t", "enumeration": [{"label": "device-modified"}, {"label": "service-modified"}]}, {"name": "identityref"}], "http://com/example/l3vpn:t7": [{"name": "http://com/example/l3vpn:t7", "enumeration": [{"label": "async"}, {"label": "timeout"}, {"label": "deleted"}]}, {"name": "string"}], "http://com/example/l3vpn:qos-match-type": [{"union": [[{"name": "ipv4-address-and-prefix-length"}], [{"name": "http://com/example/l3vpn:t2", "enumeration": [{"label": "any"}]}, {"name": "string"}]]}], "http://com/example/l3vpn:t9": [{"list_type": [{"leaf-list": true, "name": "http://com/example/l3vpn:t9"}], "leaf_type": [{"name": "string"}]}], "http://tail-f.com/ns/ncs:outformat4": [{"name": "http://tail-f.com/ns/ncs:outformat4", "enumeration": [{"info": "NCS CLI curly bracket format.", "label": "cli"}, {"info": "NETCONF XML edit-config format, i.e., the edit-config that\nwould be applied locally (at NCS) to get a config\nthat is equal to that of the managed device.", "label": "xml"}, {"info": "The actual data in native format that would be sent to\nthe device", "label": "native"}, {"label": "boolean"}]}, {"name": "string"}], "http://tail-f.com/ns/ncs:log-entry-level-t": [{"info": "Levels used for identifying the severity of an event.\nLevels are organized from least specific to most where\n'all' is least specific and 'error' is most specific.", "name": "http://tail-f.com/ns/ncs:log-entry-level-t", "enumeration": [{"label": "all"}, {"label": "trace"}, {"label": "debug"}, {"label": "info"}, {"label": "warn"}, {"label": "error"}]}, {"name": "string"}], "http://tail-f.com/ns/ncs:outformat2": [{"name": "http://tail-f.com/ns/ncs:outformat2", "enumeration": [{"info": "NCS CLI curly bracket format.", "label": "cli"}, {"info": "NETCONF XML edit-config format, i.e., the edit-config that\nwould be applied locally (at NCS) to get a config\nthat is equal to that of the managed device.", "label": "xml"}]}, {"name": "string"}]}, "keypath": "/l3vpn:vpn/l3vpn"}, "data": {"kind": "list", "leafref_groups": [["used-by-customer-service"]], "min_elements": 0, "name": "l3vpn", "max_elements": "unbounded", "qname": "l3vpn:l3vpn", "children": [{"info": {"string": "Unique service id"}, "kind": "key", "mandatory": true, "name": "name", "qname": "l3vpn:name", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "string"}}, {"info": {"string": "Devices and other services this service modified directly or\nindirectly."}, "kind": "container", "mandatory": true, "name": "modified", "leafrefGroups": [["devices"]], "qname": "l3vpn:modified", "is_config_false_callpoint": true, "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "leafref_groups": [["devices"]], "config": false, "children": [{"info": {"string": "Devices this service modified directly or indirectly"}, "kind": "leaf-list", "name": "devices", "is_leafref": true, "qname": "l3vpn:devices", "is_config_false_callpoint": true, "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "leafref_target": "/ncs:devices/device/name", "type": {"namespace": "http://com/example/l3vpn", "name": "t9"}, "config": false}, {"info": {"string": "Services this service modified directly or indirectly"}, "kind": "leaf-list", "name": "services", "type": {"namespace": "http://com/example/l3vpn", "name": "t11"}, "qname": "l3vpn:services", "is_config_false_callpoint": true, "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "config": false}, {"info": {"string": "Services residing on remote LSA nodes this service\nhas modified directly or indirectly."}, "kind": "leaf-list", "name": "lsa-services", "type": {"namespace": "http://com/example/l3vpn", "name": "t13"}, "qname": "l3vpn:lsa-services", "is_config_false_callpoint": true, "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "config": false}]}, {"info": {"string": "Devices and other services this service has explicitly\nmodified."}, "kind": "container", "mandatory": true, "name": "directly-modified", "leafrefGroups": [["devices"]], "qname": "l3vpn:directly-modified", "is_config_false_callpoint": true, "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "leafref_groups": [["devices"]], "config": false, "children": [{"info": {"string": "Devices this service has explicitly modified."}, "kind": "leaf-list", "name": "devices", "is_leafref": true, "qname": "l3vpn:devices", "is_config_false_callpoint": true, "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "leafref_target": "/ncs:devices/device/name", "type": {"namespace": "http://com/example/l3vpn", "name": "t15"}, "config": false}, {"info": {"string": "Services this service has explicitly modified."}, "kind": "leaf-list", "name": "services", "type": {"namespace": "http://com/example/l3vpn", "name": "t17"}, "qname": "l3vpn:services", "is_config_false_callpoint": true, "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "config": false}, {"info": {"string": "Services residing on remote LSA nodes this service\nhas explicitly modified."}, "kind": "leaf-list", "name": "lsa-services", "type": {"namespace": "http://com/example/l3vpn", "name": "t19"}, "qname": "l3vpn:lsa-services", "is_config_false_callpoint": true, "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "config": false}]}, {"info": {"string": "A list of devices this service instance has manipulated"}, "kind": "leaf-list", "name": "device-list", "type": {"namespace": "http://com/example/l3vpn", "name": "t21"}, "qname": "l3vpn:device-list", "is_config_false_callpoint": true, "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "config": false}, {"info": {"string": "Customer facing services using this service"}, "kind": "leaf-list", "name": "used-by-customer-service", "is_leafref": true, "qname": "l3vpn:used-by-customer-service", "is_config_false_callpoint": true, "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "leafref_target": "/ncs:services/customer-service/object-id", "type": {"namespace": "http://com/example/l3vpn", "name": "t23"}, "config": false}, {"kind": "container", "mandatory": true, "name": "commit-queue", "qname": "l3vpn:commit-queue", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false, "children": [{"kind": "list", "min_elements": 0, "name": "queue-item", "max_elements": "unbounded", "qname": "l3vpn:queue-item", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "key": ["id"], "mandatory": true, "config": false, "children": [{"kind": "key", "mandatory": true, "name": "id", "type": {"primitive": true, "name": "uint64"}, "qname": "l3vpn:id", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"kind": "leaf", "name": "status", "type": {"namespace": "http://com/example/l3vpn", "name": "t24"}, "qname": "l3vpn:status", "is_config_false_callpoint": true, "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "config": false}, {"kind": "list", "leafref_groups": [["name"]], "min_elements": 0, "name": "failed-device", "max_elements": "unbounded", "qname": "l3vpn:failed-device", "children": [{"kind": "key", "mandatory": true, "name": "name", "is_leafref": true, "qname": "l3vpn:name", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "leafref_target": "/ncs:devices/device/name", "type": {"primitive": true, "name": "string"}, "config": false}, {"kind": "leaf", "name": "time", "config": false, "qname": "l3vpn:time", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "type": {"primitive": true, "name": "date-and-time"}}, {"kind": "leaf", "name": "config-data", "is_cli_preformatted": true, "type": {"primitive": true, "name": "string"}, "qname": "l3vpn:config-data", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "config": false}, {"kind": "leaf", "name": "error", "config": false, "qname": "l3vpn:error", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "type": {"primitive": true, "name": "string"}}], "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "key": ["name"], "mandatory": true, "config": false, "leafrefGroups": [["name"]]}, {"access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}, "kind": "action", "mandatory": true, "name": "admin-clear", "qname": "l3vpn:admin-clear"}, {"access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}, "kind": "action", "mandatory": true, "name": "delete", "qname": "l3vpn:delete"}]}, {"access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}, "kind": "action", "mandatory": true, "name": "clear", "qname": "l3vpn:clear"}]}, {"kind": "container", "mandatory": true, "name": "log", "qname": "l3vpn:log", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false, "children": [{"kind": "list", "min_elements": 0, "name": "log-entry", "max_elements": "unbounded", "qname": "l3vpn:log-entry", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "key": ["when"], "mandatory": true, "config": false, "children": [{"kind": "key", "mandatory": true, "name": "when", "type": {"primitive": true, "name": "date-and-time"}, "qname": "l3vpn:when", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"kind": "leaf", "mandatory": true, "name": "type", "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "log-entry-t"}, "qname": "l3vpn:type", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"kind": "leaf", "mandatory": true, "name": "level", "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "log-entry-level-t"}, "qname": "l3vpn:level", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"kind": "leaf", "name": "message", "config": false, "qname": "l3vpn:message", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "type": {"primitive": true, "name": "string"}}]}, {"info": {"string": "Remove log entries"}, "kind": "action", "mandatory": true, "name": "purge", "qname": "l3vpn:purge", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}]}, {"kind": "leaf", "mandatory": true, "name": "route-distinguisher", "qname": "l3vpn:route-distinguisher", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "uint32"}}, {"kind": "list", "leafref_groups": [["ce-device"]], "min_elements": 0, "name": "endpoint", "max_elements": "unbounded", "qname": "l3vpn:endpoint", "children": [{"info": {"string": "Endpoint identifier"}, "kind": "key", "mandatory": true, "name": "id", "qname": "l3vpn:id", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "string"}}, {"kind": "leaf", "mandatory": true, "name": "ce-device", "type": {"primitive": true, "name": "string"}, "qname": "l3vpn:ce-device", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "leafref_target": "/ncs:devices/device/name", "is_leafref": true}, {"kind": "leaf", "mandatory": true, "name": "ce-interface", "qname": "l3vpn:ce-interface", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "string"}}, {"kind": "leaf", "mandatory": true, "name": "ip-network", "qname": "l3vpn:ip-network", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "ip-prefix"}}, {"info": {"string": "Bandwidth in bps"}, "kind": "leaf", "mandatory": true, "name": "bandwidth", "qname": "l3vpn:bandwidth", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "uint32"}}, {"info": {"string": "CE Router as-number"}, "kind": "leaf", "name": "as-number", "qname": "l3vpn:as-number", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"primitive": true, "name": "uint32"}}], "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "key": ["id"], "mandatory": true, "leafrefGroups": [["ce-device"]]}, {"kind": "container", "mandatory": true, "name": "qos", "leafrefGroups": [["qos-policy"]], "qname": "l3vpn:qos", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "leafref_groups": [["qos-policy"]], "children": [{"kind": "leaf", "name": "qos-policy", "type": {"primitive": true, "name": "string"}, "qname": "l3vpn:qos-policy", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "leafref_target": "/l3vpn:qos/qos-policy/name", "is_leafref": true}, {"kind": "list", "leafref_groups": [["qos-class"]], "min_elements": 0, "name": "custom-qos-match", "max_elements": "unbounded", "qname": "l3vpn:custom-qos-match", "children": [{"kind": "key", "mandatory": true, "name": "name", "qname": "l3vpn:name", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "string"}}, {"kind": "leaf", "mandatory": true, "name": "qos-class", "type": {"primitive": true, "name": "string"}, "qname": "l3vpn:qos-class", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "leafref_target": "/l3vpn:qos/qos-class/name", "is_leafref": true}, {"access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "kind": "leaf", "type": {"namespace": "http://com/example/l3vpn", "name": "qos-match-type"}, "name": "source-ip", "qname": "l3vpn:source-ip"}, {"access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "kind": "leaf", "type": {"namespace": "http://com/example/l3vpn", "name": "qos-match-type"}, "name": "destination-ip", "qname": "l3vpn:destination-ip"}, {"info": {"string": "Destination IP port"}, "kind": "leaf", "name": "port-start", "qname": "l3vpn:port-start", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"namespace": "urn:ietf:params:xml:ns:yang:ietf-inet-types", "name": "port-number"}}, {"info": {"string": "Destination IP port"}, "kind": "leaf", "name": "port-end", "qname": "l3vpn:port-end", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"namespace": "urn:ietf:params:xml:ns:yang:ietf-inet-types", "name": "port-number"}}, {"info": {"string": "Source IP protocol"}, "kind": "leaf", "name": "protocol", "qname": "l3vpn:protocol", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"namespace": "http://com/example/l3vpn", "name": "protocol-type"}}], "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "key": ["name"], "mandatory": true, "leafrefGroups": [["qos-class"]]}]}, {"info": {"string": "Check if device config is according to the service"}, "kind": "action", "mandatory": true, "name": "check-sync", "qname": "l3vpn:check-sync", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}, "children": [{"kind": "leaf", "is_action_input": true, "name": "outformat", "default": "boolean", "qname": "l3vpn:outformat", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "outformat4"}}, {"default": "deep", "kind": "choice", "cases": [{"kind": "case", "name": "deep", "children": [{"kind": "leaf", "is_action_input": true, "name": "deep", "qname": "l3vpn:deep", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}]}, {"kind": "case", "name": "shallow", "children": [{"kind": "leaf", "is_action_input": true, "name": "shallow", "qname": "l3vpn:shallow", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}]}], "name": "depth"}, {"info": {"string": "Return list only contains negatives"}, "kind": "leaf", "is_action_input": true, "name": "suppress-positive-result", "qname": "l3vpn:suppress-positive-result", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}, {"kind": "choice", "cases": [{"kind": "case", "name": "use-lsa", "children": [{"kind": "leaf", "is_action_input": true, "name": "use-lsa", "qname": "l3vpn:use-lsa", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}]}, {"kind": "case", "name": "no-lsa", "children": [{"kind": "leaf", "is_action_input": true, "name": "no-lsa", "qname": "l3vpn:no-lsa", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}]}], "name": "choice-lsa"}, {"kind": "choice", "cases": [{"kind": "case", "name": "in-sync", "children": [{"kind": "leaf", "name": "in-sync", "qname": "l3vpn:in-sync", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "type": {"primitive": true, "name": "boolean"}, "is_action_output": true}]}, {"kind": "case", "name": "case-xml", "children": [{"kind": "container", "mandatory": true, "name": "result-xml", "qname": "l3vpn:result-xml", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "is_action_output": true}]}, {"kind": "case", "name": "case-cli", "children": [{"kind": "container", "mandatory": true, "name": "cli", "qname": "l3vpn:cli", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "is_action_output": true}]}, {"kind": "case", "name": "case-native", "children": [{"kind": "container", "mandatory": true, "name": "native", "qname": "l3vpn:native", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "is_action_output": true}]}], "name": "outformat"}]}, {"info": {"string": "Check if device config is according to the service"}, "kind": "action", "mandatory": true, "name": "deep-check-sync", "qname": "l3vpn:deep-check-sync", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}, "children": [{"kind": "leaf", "is_action_input": true, "name": "outformat", "default": "boolean", "qname": "l3vpn:outformat", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "outformat-deep-check-sync"}}, {"info": {"string": "Return list only contains negatives"}, "kind": "leaf", "is_action_input": true, "name": "suppress-positive-result", "qname": "l3vpn:suppress-positive-result", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}, {"kind": "choice", "cases": [{"kind": "case", "name": "use-lsa", "children": [{"kind": "leaf", "is_action_input": true, "name": "use-lsa", "qname": "l3vpn:use-lsa", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}]}, {"kind": "case", "name": "no-lsa", "children": [{"kind": "leaf", "is_action_input": true, "name": "no-lsa", "qname": "l3vpn:no-lsa", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}]}], "name": "choice-lsa"}, {"kind": "choice", "cases": [{"kind": "case", "name": "case-xml", "children": [{"kind": "container", "mandatory": true, "name": "result-xml", "qname": "l3vpn:result-xml", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "is_action_output": true}]}, {"kind": "case", "name": "case-cli", "children": [{"kind": "container", "mandatory": true, "name": "cli", "qname": "l3vpn:cli", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "is_action_output": true}]}, {"kind": "case", "name": "case-sync", "children": [{"kind": "container", "mandatory": true, "name": "sync-result", "qname": "l3vpn:sync-result", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "is_action_output": true}]}], "name": "outformat"}]}, {"info": {"string": "Run/Dryrun the service logic again"}, "kind": "action", "mandatory": true, "name": "re-deploy", "qname": "l3vpn:re-deploy", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}, "children": [{"kind": "container", "is_action_input": true, "name": "dry-run", "presence": true, "qname": "l3vpn:dry-run", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}}, {"kind": "leaf", "is_action_input": true, "name": "no-revision-drop", "qname": "l3vpn:no-revision-drop", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}, {"kind": "leaf", "is_action_input": true, "name": "no-networking", "qname": "l3vpn:no-networking", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}, {"kind": "choice", "cases": [{"kind": "case", "name": "no-overwrite", "children": [{"kind": "leaf", "is_action_input": true, "name": "no-overwrite", "qname": "l3vpn:no-overwrite", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}]}, {"kind": "case", "name": "no-out-of-sync-check", "children": [{"kind": "leaf", "is_action_input": true, "name": "no-out-of-sync-check", "qname": "l3vpn:no-out-of-sync-check", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}]}], "name": "choice-sync-check"}, {"kind": "container", "is_action_input": true, "name": "commit-queue", "presence": true, "qname": "l3vpn:commit-queue", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}}, {"kind": "choice", "cases": [{"kind": "case", "name": "use-lsa", "children": [{"kind": "leaf", "is_action_input": true, "name": "use-lsa", "qname": "l3vpn:use-lsa", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}]}, {"kind": "case", "name": "no-lsa", "children": [{"kind": "leaf", "is_action_input": true, "name": "no-lsa", "qname": "l3vpn:no-lsa", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}]}], "name": "choice-lsa"}, {"default": "deep", "kind": "choice", "cases": [{"kind": "case", "name": "deep", "children": [{"kind": "leaf", "is_action_input": true, "name": "deep", "qname": "l3vpn:deep", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}]}, {"kind": "case", "name": "shallow", "children": [{"kind": "leaf", "is_action_input": true, "name": "shallow", "qname": "l3vpn:shallow", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}]}], "name": "depth"}, {"kind": "container", "is_action_input": true, "name": "reconcile", "presence": true, "qname": "l3vpn:reconcile", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}}, {"kind": "choice", "cases": [{"kind": "case", "name": "case-xml", "children": [{"kind": "container", "mandatory": true, "name": "result-xml", "qname": "l3vpn:result-xml", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "is_action_output": true}]}, {"kind": "case", "name": "case-cli", "children": [{"kind": "container", "mandatory": true, "name": "cli", "qname": "l3vpn:cli", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "is_action_output": true}]}, {"kind": "case", "name": "case-native", "children": [{"kind": "container", "mandatory": true, "name": "native", "qname": "l3vpn:native", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "is_action_output": true}]}], "name": "outformat"}, {"kind": "container", "mandatory": true, "name": "commit-queue", "qname": "l3vpn:commit-queue", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "is_action_output": true}, {"kind": "leaf", "name": "id", "type": {"primitive": true, "name": "uint64"}, "qname": "l3vpn:id", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "leafref_target": "/ncs:devices/commit-queue/queue-item/id", "is_leafref": true, "is_action_output": true}, {"kind": "leaf", "name": "tag", "qname": "l3vpn:tag", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "type": {"primitive": true, "name": "string"}, "is_action_output": true}, {"kind": "leaf", "name": "status", "qname": "l3vpn:status", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "type": {"namespace": "http://com/example/l3vpn", "name": "t7"}, "is_action_output": true}]}, {"info": {"string": "Reactive redeploy of service logic"}, "kind": "action", "mandatory": true, "name": "reactive-re-deploy", "qname": "l3vpn:reactive-re-deploy", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}, "children": [{"kind": "leaf", "name": "id", "type": {"primitive": true, "name": "uint64"}, "qname": "l3vpn:id", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "leafref_target": "/ncs:devices/commit-queue/queue-item/id", "is_leafref": true, "is_action_output": true}, {"kind": "leaf", "name": "tag", "qname": "l3vpn:tag", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "type": {"primitive": true, "name": "string"}, "is_action_output": true}, {"kind": "leaf", "name": "status", "qname": "l3vpn:status", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "type": {"namespace": "http://com/example/l3vpn", "name": "t7"}, "is_action_output": true}]}, {"info": {"string": "Touch a service"}, "kind": "action", "mandatory": true, "name": "touch", "qname": "l3vpn:touch", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}, "children": []}, {"info": {"string": "Get the data this service created"}, "kind": "action", "mandatory": true, "name": "get-modifications", "qname": "l3vpn:get-modifications", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}, "children": [{"kind": "leaf", "is_action_input": true, "name": "outformat", "qname": "l3vpn:outformat", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "outformat2"}}, {"kind": "leaf", "is_action_input": true, "name": "reverse", "qname": "l3vpn:reverse", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}, {"default": "deep", "kind": "choice", "cases": [{"kind": "case", "name": "deep", "children": [{"kind": "leaf", "is_action_input": true, "name": "deep", "qname": "l3vpn:deep", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}]}, {"kind": "case", "name": "shallow", "children": [{"kind": "leaf", "is_action_input": true, "name": "shallow", "qname": "l3vpn:shallow", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}]}], "name": "depth"}, {"kind": "choice", "cases": [{"kind": "case", "name": "use-lsa", "children": [{"kind": "leaf", "is_action_input": true, "name": "use-lsa", "qname": "l3vpn:use-lsa", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}]}, {"kind": "case", "name": "no-lsa", "children": [{"kind": "leaf", "is_action_input": true, "name": "no-lsa", "qname": "l3vpn:no-lsa", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}]}], "name": "choice-lsa"}, {"kind": "choice", "cases": [{"kind": "case", "name": "case-xml", "children": [{"kind": "container", "mandatory": true, "name": "result-xml", "qname": "l3vpn:result-xml", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "is_action_output": true}]}, {"kind": "case", "name": "case-cli", "children": [{"kind": "container", "mandatory": true, "name": "cli", "qname": "l3vpn:cli", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "is_action_output": true}]}], "name": "outformat"}]}, {"info": {"string": "Undo the effects of this service"}, "kind": "action", "mandatory": true, "name": "un-deploy", "qname": "l3vpn:un-deploy", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}, "children": [{"kind": "container", "is_action_input": true, "name": "dry-run", "presence": true, "qname": "l3vpn:dry-run", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}}, {"kind": "leaf", "is_action_input": true, "name": "no-revision-drop", "qname": "l3vpn:no-revision-drop", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}, {"kind": "leaf", "is_action_input": true, "name": "no-networking", "qname": "l3vpn:no-networking", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}, {"kind": "choice", "cases": [{"kind": "case", "name": "no-overwrite", "children": [{"kind": "leaf", "is_action_input": true, "name": "no-overwrite", "qname": "l3vpn:no-overwrite", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}]}, {"kind": "case", "name": "no-out-of-sync-check", "children": [{"kind": "leaf", "is_action_input": true, "name": "no-out-of-sync-check", "qname": "l3vpn:no-out-of-sync-check", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}]}], "name": "choice-sync-check"}, {"kind": "container", "is_action_input": true, "name": "commit-queue", "presence": true, "qname": "l3vpn:commit-queue", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}}, {"kind": "choice", "cases": [{"kind": "case", "name": "use-lsa", "children": [{"kind": "leaf", "is_action_input": true, "name": "use-lsa", "qname": "l3vpn:use-lsa", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}]}, {"kind": "case", "name": "no-lsa", "children": [{"kind": "leaf", "is_action_input": true, "name": "no-lsa", "qname": "l3vpn:no-lsa", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}]}], "name": "choice-lsa"}, {"kind": "leaf", "is_action_input": true, "name": "ignore-refcount", "qname": "l3vpn:ignore-refcount", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}, {"kind": "choice", "cases": [{"kind": "case", "name": "case-xml", "children": [{"kind": "container", "mandatory": true, "name": "result-xml", "qname": "l3vpn:result-xml", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "is_action_output": true}]}, {"kind": "case", "name": "case-cli", "children": [{"kind": "container", "mandatory": true, "name": "cli", "qname": "l3vpn:cli", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "is_action_output": true}]}, {"kind": "case", "name": "case-native", "children": [{"kind": "container", "mandatory": true, "name": "native", "qname": "l3vpn:native", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "is_action_output": true}]}], "name": "outformat"}, {"kind": "container", "mandatory": true, "name": "commit-queue", "qname": "l3vpn:commit-queue", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "is_action_output": true}, {"kind": "leaf", "name": "id", "type": {"primitive": true, "name": "uint64"}, "qname": "l3vpn:id", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "leafref_target": "/ncs:devices/commit-queue/queue-item/id", "is_leafref": true, "is_action_output": true}, {"kind": "leaf", "name": "tag", "qname": "l3vpn:tag", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "type": {"primitive": true, "name": "string"}, "is_action_output": true}, {"kind": "leaf", "name": "status", "qname": "l3vpn:status", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "type": {"namespace": "http://com/example/l3vpn", "name": "t7"}, "is_action_output": true}]}], "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "key": ["name"], "mandatory": true, "leafrefGroups": [["used-by-customer-service"]]}} diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/l3vpn_schema.json b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/l3vpn_schema.json new file mode 100644 index 00000000..0e7e3703 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/l3vpn_schema.json @@ -0,0 +1 @@ +{"meta": {"prefix": "l3vpn", "namespace": "http://com/example/l3vpn", "types": {"http://com/example/l3vpn:t21": [{"list_type": [{"leaf-list": true, "name": "http://com/example/l3vpn:t21"}], "leaf_type": [{"name": "string"}]}], "http://com/example/l3vpn:t23": [{"list_type": [{"leaf-list": true, "name": "http://com/example/l3vpn:t23"}], "leaf_type": [{"name": "string"}]}]}, "keypath": "/l3vpn:vpn"}, "data": {"kind": "container", "mandatory": true, "name": "vpn", "qname": "l3vpn:vpn", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "children": [{"kind": "list", "leafref_groups": [["used-by-customer-service"]], "min_elements": 0, "name": "l3vpn", "max_elements": "unbounded", "qname": "l3vpn:l3vpn", "children": [{"info": {"string": "Unique service id"}, "kind": "key", "mandatory": true, "name": "name", "qname": "l3vpn:name", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "string"}}, {"info": {"string": "Devices and other services this service modified directly or\nindirectly."}, "kind": "container", "mandatory": true, "name": "modified", "leafrefGroups": [["devices"]], "qname": "l3vpn:modified", "is_config_false_callpoint": true, "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "leafref_groups": [["devices"]], "config": false}, {"info": {"string": "Devices and other services this service has explicitly\nmodified."}, "kind": "container", "mandatory": true, "name": "directly-modified", "leafrefGroups": [["devices"]], "qname": "l3vpn:directly-modified", "is_config_false_callpoint": true, "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "leafref_groups": [["devices"]], "config": false}, {"info": {"string": "A list of devices this service instance has manipulated"}, "kind": "leaf-list", "name": "device-list", "type": {"namespace": "http://com/example/l3vpn", "name": "t21"}, "qname": "l3vpn:device-list", "is_config_false_callpoint": true, "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "config": false}, {"info": {"string": "Customer facing services using this service"}, "kind": "leaf-list", "name": "used-by-customer-service", "is_leafref": true, "qname": "l3vpn:used-by-customer-service", "is_config_false_callpoint": true, "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "leafref_target": "/ncs:services/customer-service/object-id", "type": {"namespace": "http://com/example/l3vpn", "name": "t23"}, "config": false}, {"kind": "container", "mandatory": true, "name": "commit-queue", "qname": "l3vpn:commit-queue", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"kind": "container", "mandatory": true, "name": "log", "qname": "l3vpn:log", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"kind": "leaf", "mandatory": true, "name": "route-distinguisher", "qname": "l3vpn:route-distinguisher", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "uint32"}}, {"kind": "list", "leafref_groups": [["ce-device"]], "min_elements": 0, "name": "endpoint", "max_elements": "unbounded", "qname": "l3vpn:endpoint", "children": [{"info": {"string": "Endpoint identifier"}, "kind": "key", "mandatory": true, "name": "id", "qname": "l3vpn:id", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "string"}}, {"kind": "leaf", "mandatory": true, "name": "ce-device", "type": {"primitive": true, "name": "string"}, "qname": "l3vpn:ce-device", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "leafref_target": "/ncs:devices/device/name", "is_leafref": true}, {"kind": "leaf", "mandatory": true, "name": "ce-interface", "qname": "l3vpn:ce-interface", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "string"}}, {"kind": "leaf", "mandatory": true, "name": "ip-network", "qname": "l3vpn:ip-network", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "ip-prefix"}}, {"info": {"string": "Bandwidth in bps"}, "kind": "leaf", "mandatory": true, "name": "bandwidth", "qname": "l3vpn:bandwidth", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "uint32"}}, {"info": {"string": "CE Router as-number"}, "kind": "leaf", "name": "as-number", "qname": "l3vpn:as-number", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"primitive": true, "name": "uint32"}}], "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "key": ["id"], "mandatory": true, "leafrefGroups": [["ce-device"]]}, {"kind": "container", "mandatory": true, "name": "qos", "leafrefGroups": [["qos-policy"]], "qname": "l3vpn:qos", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "leafref_groups": [["qos-policy"]]}, {"info": {"string": "Check if device config is according to the service"}, "kind": "action", "mandatory": true, "name": "check-sync", "qname": "l3vpn:check-sync", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Check if device config is according to the service"}, "kind": "action", "mandatory": true, "name": "deep-check-sync", "qname": "l3vpn:deep-check-sync", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Run/Dryrun the service logic again"}, "kind": "action", "mandatory": true, "name": "re-deploy", "qname": "l3vpn:re-deploy", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Reactive redeploy of service logic"}, "kind": "action", "mandatory": true, "name": "reactive-re-deploy", "qname": "l3vpn:reactive-re-deploy", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Touch a service"}, "kind": "action", "mandatory": true, "name": "touch", "qname": "l3vpn:touch", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Get the data this service created"}, "kind": "action", "mandatory": true, "name": "get-modifications", "qname": "l3vpn:get-modifications", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Undo the effects of this service"}, "kind": "action", "mandatory": true, "name": "un-deploy", "qname": "l3vpn:un-deploy", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}], "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "key": ["name"], "mandatory": true, "leafrefGroups": [["used-by-customer-service"]]}]}} diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/sync_from_schema.json b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/sync_from_schema.json new file mode 100644 index 00000000..dc2206d4 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/sync_from_schema.json @@ -0,0 +1,178 @@ +{ + "meta": { + "prefix": "ncs", + "namespace": "http://tail-f.com/ns/ncs", + "types": { + "http://tail-f.com/ns/ncs:outformat2": [ + { + "name": "http://tail-f.com/ns/ncs:outformat2", + "enumeration": [ + { + "info": "NCS CLI curly bracket format.", + "label": "cli" + }, + { + "info": "NETCONF XML edit-config format, i.e., the edit-config that\nwould be applied locally (at NCS) to get a config\nthat is equal to that of the managed device.", + "label": "xml" + } + ] + }, + { + "name": "string" + } + ] + }, + "keypath": "/ncs:devices/device{ce0}/sync-from" + }, + "data": { + "info": { + "string": "Synchronize the config by pulling from the device" + }, + "kind": "action", + "mandatory": true, + "name": "sync-from", + "qname": "ncs:sync-from", + "access": { + "read": false, + "create": false, + "execute": true, + "update": false, + "delete": false + }, + "children": [ + { + "kind": "container", + "is_action_input": true, + "name": "dry-run", + "presence": true, + "qname": "ncs:dry-run", + "access": { + "read": false, + "create": false, + "execute": false, + "update": true, + "delete": false + }, + "children": [ + { + "info": { + "string": "Report what would be done towards CDB, without\nactually doing anything." + }, + "kind": "leaf", + "is_action_input": true, + "name": "outformat", + "qname": "ncs:outformat", + "access": { + "read": false, + "create": false, + "execute": false, + "update": true, + "delete": false + }, + "type": { + "namespace": "http://tail-f.com/ns/ncs", + "name": "outformat2" + } + } + ] + }, + { + "kind": "choice", + "cases": [ + { + "kind": "case", + "name": "result", + "children": [ + { + "kind": "leaf", + "name": "result", + "qname": "ncs:result", + "access": { + "read": false, + "create": false, + "execute": false, + "update": false, + "delete": false + }, + "type": { + "primitive": true, + "name": "boolean" + }, + "is_action_output": true + } + ] + }, + { + "kind": "case", + "name": "result-xml", + "children": [ + { + "kind": "leaf", + "name": "result-xml", + "is_cli_preformatted": true, + "qname": "ncs:result-xml", + "access": { + "read": false, + "create": false, + "execute": false, + "update": false, + "delete": false + }, + "type": { + "primitive": true, + "name": "string" + }, + "is_action_output": true + } + ] + }, + { + "kind": "case", + "name": "cli", + "children": [ + { + "kind": "leaf", + "name": "cli", + "is_cli_preformatted": true, + "qname": "ncs:cli", + "access": { + "read": false, + "create": false, + "execute": false, + "update": false, + "delete": false + }, + "type": { + "primitive": true, + "name": "string" + }, + "is_action_output": true + } + ] + } + ], + "name": "outformat" + }, + { + "info": { + "string": "If present, contains additional information about the result." + }, + "kind": "leaf", + "name": "info", + "qname": "ncs:info", + "access": { + "read": false, + "create": false, + "execute": false, + "update": false, + "delete": false + }, + "type": { + "primitive": true, + "name": "string" + }, + "is_action_output": true + } + ] + } +} diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/verify_violation_data.json b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/verify_violation_data.json new file mode 100644 index 00000000..05742c11 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/verify_violation_data.json @@ -0,0 +1,10 @@ +{ + "tailf-ncs:devices": { + "device": [ + { + "name": "ce0", + "description": "Example Device" + } + ] + } +} diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/nso_module.py b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/nso_module.py new file mode 100644 index 00000000..87bcb27b --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/nso_module.py @@ -0,0 +1,132 @@ +# Copyright (c) 2017 Cisco and/or its affiliates. +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +import os +import json + +from ansible_collections.cisco.nso.tests.unit.compat import unittest +from ansible_collections.cisco.nso.tests.unit.compat.mock import patch +from ansible.module_utils import basic + + +fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') +fixture_data = {} + + +def load_fixture(name): + path = os.path.join(fixture_path, name) + if path not in fixture_data: + with open(path) as f: + data = json.load(f) + fixture_data[path] = data + return fixture_data[path] + + +class MockResponse(object): + def __init__(self, method, params, code, body, headers=None): + if headers is None: + headers = {} + + self.method = method + self.params = params + + self.code = code + self.body = body + self.headers = dict(headers) + + def read(self): + return self.body + + +def mock_call(calls, url, timeout, validate_certs, data=None, headers=None, method=None): + if len(calls) == 0: + raise ValueError('no call mock for method {0}({1})'.format( + url, data)) + + result = calls[0] + del calls[0] + + request = json.loads(data) + if result.method != request['method']: + raise ValueError('expected method {0}({1}), got {2}({3})'.format( + result.method, result.params, + request['method'], request['params'])) + + for key, value in result.params.items(): + if key not in request['params']: + raise ValueError('{0} not in parameters'.format(key)) + if value != request['params'][key]: + raise ValueError('expected {0} to be {1}, got {2}'.format( + key, value, request['params'][key])) + + return result + + +class AnsibleExitJson(Exception): + pass + + +class AnsibleFailJson(Exception): + pass + + +class TestNsoModule(unittest.TestCase): + + def execute_module(self, failed=False, changed=False, **kwargs): + if failed: + result = self.failed() + self.assertTrue(result['failed'], result) + else: + result = self.changed(changed) + self.assertEqual(result['changed'], changed, result) + + for key, value in kwargs.items(): + if key not in result: + self.fail("{0} not in result {1}".format(key, result)) + self.assertEqual(value, result[key]) + + return result + + def failed(self): + def fail_json(*args, **kwargs): + kwargs['failed'] = True + raise AnsibleFailJson(kwargs) + + with patch.object(basic.AnsibleModule, 'fail_json', fail_json): + with self.assertRaises(AnsibleFailJson) as exc: + self.module.main() + + result = exc.exception.args[0] + self.assertTrue(result['failed'], result) + return result + + def changed(self, changed=False): + def exit_json(*args, **kwargs): + if 'changed' not in kwargs: + kwargs['changed'] = False + raise AnsibleExitJson(kwargs) + + with patch.object(basic.AnsibleModule, 'exit_json', exit_json): + with self.assertRaises(AnsibleExitJson) as exc: + self.module.main() + + result = exc.exception.args[0] + self.assertEqual(result['changed'], changed, result) + return result diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/test_nso_action.py b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/test_nso_action.py new file mode 100644 index 00000000..be93f3b8 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/test_nso_action.py @@ -0,0 +1,167 @@ +# +# Copyright (c) 2017 Cisco and/or its affiliates. +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +import json + +from ansible_collections.cisco.nso.tests.unit.compat.mock import patch +from ansible_collections.cisco.nso.plugins.modules import nso_action +from . import nso_module +from .nso_module import MockResponse + +from ansible_collections.cisco.nso.tests.unit.plugins.modules.utils import set_module_args + + +class TestNsoAction(nso_module.TestNsoModule): + module = nso_action + + @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url') + def test_nso_action_missing(self, open_url_mock): + action_input = {} + path = '/ncs:devices/device{ce0}/missing' + calls = [ + MockResponse('login', {}, 200, '{}', {'set-cookie': 'id'}), + MockResponse('get_system_setting', {'operation': 'version'}, 200, '{"result": "4.5.0"}'), + MockResponse('new_trans', {'mode': 'read'}, 200, '{"result": {"th": 1}}'), + MockResponse('get_schema', {'path': path}, 200, '{"error": {"data": {"param": "path"}, "type": "rpc.method.invalid_params"}}'), + MockResponse('logout', {}, 200, '{"result": {}}'), + ] + open_url_mock.side_effect = lambda *args, **kwargs: nso_module.mock_call(calls, *args, **kwargs) + + set_module_args({ + 'username': 'user', 'password': 'password', + 'url': 'http://localhost:8080/jsonrpc', + 'path': path, + 'input': action_input, + 'validate_certs': False + }) + self.execute_module(failed=True, msg='NSO get_schema invalid params. path = /ncs:devices/device{ce0}/missing') + + self.assertEqual(0, len(calls)) + + @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url') + def test_nso_action_not_action(self, open_url_mock): + action_input = {} + path = '/ncs:devices/device{ce0}/description' + schema = nso_module.load_fixture('description_schema.json') + calls = [ + MockResponse('login', {}, 200, '{}', {'set-cookie': 'id'}), + MockResponse('get_system_setting', {'operation': 'version'}, 200, '{"result": "4.5.0"}'), + MockResponse('new_trans', {'mode': 'read'}, 200, '{"result": {"th": 1}}'), + MockResponse('get_schema', {'path': path}, 200, '{"result": %s}' % (json.dumps(schema, ))), + MockResponse('logout', {}, 200, '{"result": {}}'), + ] + open_url_mock.side_effect = lambda *args, **kwargs: nso_module.mock_call(calls, *args, **kwargs) + + set_module_args({ + 'username': 'user', 'password': 'password', + 'url': 'http://localhost:8080/jsonrpc', + 'path': path, + 'input': action_input, + 'validate_certs': False + }) + self.execute_module(failed=True, msg='/ncs:devices/device{ce0}/description is not an action') + + self.assertEqual(0, len(calls)) + + @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url') + def test_nso_action_ok(self, open_url_mock): + action_input = {} + path = '/ncs:devices/device{ce0}/sync-from' + output = {"result": True} + schema = nso_module.load_fixture('sync_from_schema.json') + calls = [ + MockResponse('login', {}, 200, '{}', {'set-cookie': 'id'}), + MockResponse('get_system_setting', {'operation': 'version'}, 200, '{"result": "4.5.0"}'), + MockResponse('new_trans', {'mode': 'read'}, 200, '{"result": {"th": 1}}'), + MockResponse('get_schema', {'path': path}, 200, '{"result": %s}' % (json.dumps(schema, ))), + MockResponse('run_action', {'path': path, 'params': action_input}, 200, '{"result": {"result": true}}'), + MockResponse('logout', {}, 200, '{"result": {}}'), + ] + open_url_mock.side_effect = lambda *args, **kwargs: nso_module.mock_call(calls, *args, **kwargs) + + set_module_args({ + 'username': 'user', 'password': 'password', + 'url': 'http://localhost:8080/jsonrpc', + 'path': path, + 'input': action_input, + 'validate_certs': False + }) + self.execute_module(changed=True, output=output) + + self.assertEqual(0, len(calls)) + + @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url') + def test_nso_action_validate_ok(self, open_url_mock): + action_input = {} + path = '/test:action' + output = {'version': [{'name': 'v1'}, {'name': 'v2'}]} + schema = nso_module.load_fixture('complex_schema.json') + calls = [ + MockResponse('login', {}, 200, '{}', {'set-cookie': 'id'}), + MockResponse('get_system_setting', {'operation': 'version'}, 200, '{"result": "4.5.0"}'), + MockResponse('new_trans', {'mode': 'read'}, 200, '{"result": {"th": 1}}'), + MockResponse('get_schema', {'path': path}, 200, '{"result": %s}' % (json.dumps(schema, ))), + MockResponse('run_action', {'path': path, 'params': action_input}, 200, + '{"result": {"version": [{"name": "v1"}, {"name": "v2"}]}}'), + MockResponse('logout', {}, 200, '{"result": {}}'), + ] + open_url_mock.side_effect = lambda *args, **kwargs: nso_module.mock_call(calls, *args, **kwargs) + + set_module_args({ + 'username': 'user', 'password': 'password', + 'url': 'http://localhost:8080/jsonrpc', + 'path': path, + 'input': action_input, + 'output_required': output, + 'validate_certs': False + }) + self.execute_module(changed=True, output=output) + + self.assertEqual(0, len(calls)) + + @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url') + def test_nso_action_validate_failed(self, open_url_mock): + action_input = {} + path = '/test:action' + output_mismatch = {'version': [{'name': 'v1'}, {'name': 'v3'}]} + schema = nso_module.load_fixture('complex_schema.json') + calls = [ + MockResponse('login', {}, 200, '{}', {'set-cookie': 'id'}), + MockResponse('get_system_setting', {'operation': 'version'}, 200, '{"result": "4.5.0"}'), + MockResponse('new_trans', {'mode': 'read'}, 200, '{"result": {"th": 1}}'), + MockResponse('get_schema', {'path': path}, 200, '{"result": %s}' % (json.dumps(schema, ))), + MockResponse('run_action', {'path': path, 'params': action_input}, 200, + '{"result": {"version": [{"name": "v1"}, {"name": "v2"}]}}'), + MockResponse('logout', {}, 200, '{"result": {}}'), + ] + open_url_mock.side_effect = lambda *args, **kwargs: nso_module.mock_call(calls, *args, **kwargs) + + set_module_args({ + 'username': 'user', 'password': 'password', + 'url': 'http://localhost:8080/jsonrpc', + 'path': path, + 'input': action_input, + 'output_required': output_mismatch, + 'validate_certs': False + }) + self.execute_module(failed=True, msg="version value mismatch. expected [{'name': 'v1'}, {'name': 'v3'}] got [{'name': 'v1'}, {'name': 'v2'}]") + + self.assertEqual(0, len(calls)) diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/test_nso_config.py b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/test_nso_config.py new file mode 100644 index 00000000..25087e8e --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/test_nso_config.py @@ -0,0 +1,138 @@ +# +# Copyright (c) 2017 Cisco and/or its affiliates. +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +import json + +from ansible_collections.cisco.nso.tests.unit.compat.mock import patch +from ansible_collections.cisco.nso.plugins.modules import nso_config +from ansible_collections.cisco.nso.tests.unit.plugins.modules.utils import set_module_args +from . import nso_module +from .nso_module import MockResponse + + +class TestNsoConfig(nso_module.TestNsoModule): + module = nso_config + + @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url') + def test_nso_config_invalid_version_short(self, open_url_mock): + self._test_invalid_version(open_url_mock, '3.3') + + @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url') + def test_nso_config_invalid_version_long(self, open_url_mock): + self._test_invalid_version(open_url_mock, '3.3.2') + + def _test_invalid_version(self, open_url_mock, version): + calls = [ + MockResponse('login', {}, 200, '{}', {'set-cookie': 'id'}), + MockResponse('get_system_setting', {'operation': 'version'}, 200, '{"result": "%s"}' % (version, )), + MockResponse('logout', {}, 200, '{"result": {}}'), + ] + open_url_mock.side_effect = lambda *args, **kwargs: nso_module.mock_call(calls, *args, **kwargs) + + data = nso_module.load_fixture('config_config.json') + set_module_args({ + 'username': 'user', 'password': 'password', + 'url': 'http://localhost:8080/jsonrpc', 'data': data, + 'validate_certs': False + }) + self.execute_module(failed=True) + + self.assertEqual(0, len(calls)) + + @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url') + def test_nso_config_valid_version_short(self, open_url_mock): + self._test_valid_version(open_url_mock, '4.5') + + @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url') + def test_nso_config_valid_version_long(self, open_url_mock): + self._test_valid_version(open_url_mock, '4.4.3') + + def _test_valid_version(self, open_url_mock, version): + calls = [ + MockResponse('login', {}, 200, '{}', {'set-cookie': 'id'}), + MockResponse('get_system_setting', {'operation': 'version'}, 200, '{"result": "%s"}' % (version, )), + MockResponse('new_trans', {}, 200, '{"result": {"th": 1}}'), + MockResponse('get_trans_changes', {}, 200, '{"result": {"changes": []}}'), + MockResponse('delete_trans', {}, 200, '{"result": {}}'), + MockResponse('logout', {}, 200, '{"result": {}}'), + ] + open_url_mock.side_effect = lambda *args, **kwargs: nso_module.mock_call(calls, *args, **kwargs) + + data = nso_module.load_fixture('config_empty_data.json') + set_module_args({ + 'username': 'user', 'password': 'password', + 'url': 'http://localhost:8080/jsonrpc', 'data': data, + 'validate_certs': False + }) + self.execute_module(changed=False, changes=[], diffs=[]) + + self.assertEqual(0, len(calls)) + + @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url') + def test_nso_config_changed(self, open_url_mock): + vpn_schema = nso_module.load_fixture('l3vpn_schema.json') + l3vpn_schema = nso_module.load_fixture('l3vpn_l3vpn_schema.json') + endpoint_schema = nso_module.load_fixture('l3vpn_l3vpn_endpoint_schema.json') + changes = nso_module.load_fixture('config_config_changes.json') + + calls = [ + MockResponse('login', {}, 200, '{}', {'set-cookie': 'id'}), + MockResponse('get_system_setting', {'operation': 'version'}, 200, '{"result": "4.5.1"}'), + MockResponse('get_module_prefix_map', {}, 200, '{"result": {"l3vpn": "l3vpn"}}'), + MockResponse('new_trans', {'mode': 'read'}, 200, '{"result": {"th": 1}}'), + MockResponse('get_schema', {'path': '/l3vpn:vpn'}, 200, '{"result": %s}' % (json.dumps(vpn_schema, ))), + MockResponse('get_schema', {'path': '/l3vpn:vpn/l3vpn'}, 200, '{"result": %s}' % (json.dumps(l3vpn_schema, ))), + MockResponse('exists', {'path': '/l3vpn:vpn/l3vpn{company}'}, 200, '{"result": {"exists": true}}'), + MockResponse('get_schema', {'path': '/l3vpn:vpn/l3vpn/endpoint'}, 200, '{"result": %s}' % (json.dumps(endpoint_schema, ))), + MockResponse('exists', {'path': '/l3vpn:vpn/l3vpn{company}/endpoint{branch-office1}'}, 200, '{"result": {"exists": false}}'), + MockResponse('new_trans', {'mode': 'read_write'}, 200, '{"result": {"th": 2}}'), + MockResponse('create', {'path': '/l3vpn:vpn/l3vpn{company}/endpoint{branch-office1}'}, 200, '{"result": {}}'), + MockResponse('set_value', {'path': '/l3vpn:vpn/l3vpn{company}/route-distinguisher', 'value': 999}, 200, '{"result": {}}'), + MockResponse('set_value', {'path': '/l3vpn:vpn/l3vpn{company}/endpoint{branch-office1}/as-number', 'value': 65101}, 200, '{"result": {}}'), + MockResponse('set_value', {'path': '/l3vpn:vpn/l3vpn{company}/endpoint{branch-office1}/bandwidth', 'value': 12000000}, 200, '{"result": {}}'), + MockResponse('set_value', {'path': '/l3vpn:vpn/l3vpn{company}/endpoint{branch-office1}/ce-device', 'value': 'ce6'}, 200, '{"result": {}}'), + MockResponse('set_value', {'path': '/l3vpn:vpn/l3vpn{company}/endpoint{branch-office1}/ce-interface', + 'value': 'GigabitEthernet0/12'}, 200, '{"result": {}}'), + MockResponse('set_value', {'path': '/l3vpn:vpn/l3vpn{company}/endpoint{branch-office1}/ip-network', + 'value': '10.10.1.0/24'}, 200, '{"result": {}}'), + MockResponse('get_trans_changes', {}, 200, '{"result": %s}' % (json.dumps(changes), )), + MockResponse('validate_commit', {}, 200, '{"result": {}}'), + MockResponse('commit', {}, 200, '{"result": {}}'), + MockResponse('logout', {}, 200, '{"result": {}}'), + ] + open_url_mock.side_effect = lambda *args, **kwargs: nso_module.mock_call(calls, *args, **kwargs) + + data = nso_module.load_fixture('config_config.json') + set_module_args({ + 'username': 'user', 'password': 'password', + 'url': 'http://localhost:8080/jsonrpc', 'data': data, + 'validate_certs': False + }) + self.execute_module(changed=True, changes=[ + {'path': '/l3vpn:vpn/l3vpn{company}/endpoint{branch-office1}/ce-device', 'type': 'set', 'from': None, 'to': 'ce6'}, + {'path': '/l3vpn:vpn/l3vpn{company}/endpoint{branch-office1}/ip-network', 'type': 'set', 'from': None, 'to': '10.10.1.0/24'}, + {'path': '/l3vpn:vpn/l3vpn{company}/endpoint{branch-office1}/as-number', 'type': 'set', 'from': None, 'to': '65101'}, + {'path': '/l3vpn:vpn/l3vpn{company}/endpoint{branch-office1}/ce-interface', 'type': 'set', 'from': None, 'to': 'GigabitEthernet0/12'}, + {'path': '/l3vpn:vpn/l3vpn{company}/endpoint{branch-office1}/bandwidth', 'type': 'set', 'from': None, 'to': '12000000'}, + {'path': '/l3vpn:vpn/l3vpn{company}/endpoint{branch-office1}', 'type': 'create'}, + ], diffs=[]) + + self.assertEqual(0, len(calls)) diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/test_nso_query.py b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/test_nso_query.py new file mode 100644 index 00000000..204478fb --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/test_nso_query.py @@ -0,0 +1,57 @@ +# +# Copyright (c) 2017 Cisco and/or its affiliates. +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +from ansible_collections.cisco.nso.tests.unit.compat.mock import patch +from ansible_collections.cisco.nso.plugins.modules import nso_query +from . import nso_module +from .nso_module import MockResponse + +from ansible_collections.cisco.nso.tests.unit.plugins.modules.utils import set_module_args + + +class TestNsoQuery(nso_module.TestNsoModule): + module = nso_query + + @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url') + def test_nso_query(self, open_url_mock): + xpath = '/packages/package' + fields = ['name', 'package-version'] + calls = [ + MockResponse('login', {}, 200, '{}', {'set-cookie': 'id'}), + MockResponse('get_system_setting', {'operation': 'version'}, 200, '{"result": "4.5"}'), + MockResponse('new_trans', {'mode': 'read'}, 200, '{"result": {"th": 1}}'), + MockResponse('query', + {'xpath_expr': xpath, 'selection': fields}, 200, + '{"result": {"results": [["test", "1.0"]]}}'), + MockResponse('logout', {}, 200, '{"result": {}}'), + ] + open_url_mock.side_effect = lambda *args, **kwargs: nso_module.mock_call(calls, *args, **kwargs) + + set_module_args({ + 'username': 'user', 'password': 'password', + 'url': 'http://localhost:8080/jsonrpc', + 'xpath': xpath, + 'fields': fields, + 'validate_certs': False + }) + self.execute_module(changed=False, output=[["test", "1.0"]]) + + self.assertEqual(0, len(calls)) diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/test_nso_show.py b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/test_nso_show.py new file mode 100644 index 00000000..2b4e28f5 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/test_nso_show.py @@ -0,0 +1,98 @@ +# +# Copyright (c) 2017 Cisco and/or its affiliates. +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +from ansible_collections.cisco.nso.tests.unit.compat.mock import patch +from ansible_collections.cisco.nso.plugins.modules import nso_show +from . import nso_module +from .nso_module import MockResponse + +from ansible_collections.cisco.nso.tests.unit.plugins.modules.utils import set_module_args + + +class TestNsoShow(nso_module.TestNsoModule): + module = nso_show + + @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url') + def test_nso_show_missing(self, open_url_mock): + path = '/ncs:devices/device{ce0}/missing' + calls = [ + MockResponse('login', {}, 200, '{}', {'set-cookie': 'id'}), + MockResponse('get_system_setting', {'operation': 'version'}, 200, '{"result": "4.5"}'), + MockResponse('new_trans', {'mode': 'read'}, 200, '{"result": {"th": 1}}'), + MockResponse('show_config', + {'path': path, 'result_as': 'json'}, 200, + '{"error": {"data": {"param": "path"}, "type": "rpc.method.invalid_params"}}'), + MockResponse('logout', {}, 200, '{"result": {}}'), + ] + open_url_mock.side_effect = lambda *args, **kwargs: nso_module.mock_call(calls, *args, **kwargs) + + set_module_args({ + 'username': 'user', 'password': 'password', + 'url': 'http://localhost:8080/jsonrpc', + 'path': path + }) + self.execute_module(failed=True, msg='NSO show_config invalid params. path = /ncs:devices/device{ce0}/missing') + + self.assertEqual(0, len(calls)) + + @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url') + def test_nso_show_config(self, open_url_mock): + path = '/ncs:devices/device{ce0}' + calls = [ + MockResponse('login', {}, 200, '{}', {'set-cookie': 'id'}), + MockResponse('get_system_setting', {'operation': 'version'}, 200, '{"result": "4.5"}'), + MockResponse('new_trans', {'mode': 'read'}, 200, '{"result": {"th": 1}}'), + MockResponse('show_config', {'path': path, 'result_as': 'json'}, 200, '{"result": {"data": {}}}'), + MockResponse('logout', {}, 200, '{"result": {}}'), + ] + open_url_mock.side_effect = lambda *args, **kwargs: nso_module.mock_call(calls, *args, **kwargs) + + set_module_args({ + 'username': 'user', 'password': 'password', + 'url': 'http://localhost:8080/jsonrpc', + 'path': path, + 'operational': False + }) + self.execute_module(changed=False, output={"data": {}}) + self.assertEqual(0, len(calls)) + + @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url') + def test_nso_show_config_and_oper(self, open_url_mock): + path = '/ncs:devices/device{ce0}/sync-from' + calls = [ + MockResponse('login', {}, 200, '{}', {'set-cookie': 'id'}), + MockResponse('get_system_setting', {'operation': 'version'}, 200, '{"result": "4.5"}'), + MockResponse('new_trans', {'mode': 'read'}, 200, '{"result": {"th": 1}}'), + MockResponse('show_config', {'path': path, 'result_as': 'json'}, 200, '{"result": {"data": {}}}'), + MockResponse('logout', {}, 200, '{"result": {}}'), + ] + open_url_mock.side_effect = lambda *args, **kwargs: nso_module.mock_call(calls, *args, **kwargs) + + set_module_args({ + 'username': 'user', 'password': 'password', + 'url': 'http://localhost:8080/jsonrpc', + 'path': path, + 'operational': True, + 'validate_certs': False + }) + self.execute_module(changed=False, output={"data": {}}) + + self.assertEqual(0, len(calls)) diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/test_nso_verify.py b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/test_nso_verify.py new file mode 100644 index 00000000..1e485d75 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/test_nso_verify.py @@ -0,0 +1,110 @@ +# +# Copyright (c) 2017 Cisco and/or its affiliates. +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +import json + +from ansible_collections.cisco.nso.tests.unit.compat.mock import patch +from ansible_collections.cisco.nso.plugins.modules import nso_verify +from . import nso_module +from .nso_module import MockResponse + +from ansible_collections.cisco.nso.tests.unit.plugins.modules.utils import set_module_args + + +class TestNsoVerify(nso_module.TestNsoModule): + module = nso_verify + + @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url') + def test_nso_verify_empty_data(self, open_url_mock): + calls = [ + MockResponse('login', {}, 200, '{}', {'set-cookie': 'id'}), + MockResponse('get_system_setting', {'operation': 'version'}, 200, '{"result": "4.4.3"}'), + MockResponse('logout', {}, 200, '{"result": {}}'), + ] + open_url_mock.side_effect = lambda *args, **kwargs: nso_module.mock_call(calls, *args, **kwargs) + + data = {} + set_module_args({ + 'username': 'user', 'password': 'password', + 'url': 'http://localhost:8080/jsonrpc', 'data': data + }) + self.execute_module(changed=False) + + self.assertEqual(0, len(calls)) + + @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url') + def test_nso_verify_violation(self, open_url_mock): + devices_schema = nso_module.load_fixture('devices_schema.json') + device_schema = nso_module.load_fixture('device_schema.json') + description_schema = nso_module.load_fixture('description_schema.json') + + calls = [ + MockResponse('login', {}, 200, '{}', {'set-cookie': 'id'}), + MockResponse('get_system_setting', {'operation': 'version'}, 200, '{"result": "4.5.0"}'), + MockResponse('get_module_prefix_map', {}, 200, '{"result": {"tailf-ncs": "ncs"}}'), + MockResponse('new_trans', {'mode': 'read'}, 200, '{"result": {"th": 1}}'), + MockResponse('get_schema', {'path': '/ncs:devices'}, 200, '{"result": %s}' % (json.dumps(devices_schema, ))), + MockResponse('get_schema', {'path': '/ncs:devices/device'}, 200, '{"result": %s}' % (json.dumps(device_schema, ))), + MockResponse('exists', {'path': '/ncs:devices/device{ce0}'}, 200, '{"result": {"exists": true}}'), + MockResponse('get_value', {'path': '/ncs:devices/device{ce0}/description'}, 200, '{"result": {"value": "In Violation"}}'), + MockResponse('get_schema', {'path': '/ncs:devices/device/description'}, 200, '{"result": %s}' % (json.dumps(description_schema, ))), + MockResponse('logout', {}, 200, '{"result": {}}'), + ] + open_url_mock.side_effect = lambda *args, **kwargs: nso_module.mock_call(calls, *args, **kwargs) + + data = nso_module.load_fixture('verify_violation_data.json') + set_module_args({ + 'username': 'user', 'password': 'password', + 'url': 'http://localhost:8080/jsonrpc', 'data': data + }) + self.execute_module(failed=True, violations=[ + {'path': '/ncs:devices/device{ce0}/description', 'expected-value': 'Example Device', 'value': 'In Violation'}, + ]) + + self.assertEqual(0, len(calls)) + + @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url') + def test_nso_verify_ok(self, open_url_mock): + devices_schema = nso_module.load_fixture('devices_schema.json') + device_schema = nso_module.load_fixture('device_schema.json') + + calls = [ + MockResponse('login', {}, 200, '{}', {'set-cookie': 'id'}), + MockResponse('get_system_setting', {'operation': 'version'}, 200, '{"result": "4.5.0"}'), + MockResponse('get_module_prefix_map', {}, 200, '{"result": {"tailf-ncs": "ncs"}}'), + MockResponse('new_trans', {'mode': 'read'}, 200, '{"result": {"th": 1}}'), + MockResponse('get_schema', {'path': '/ncs:devices'}, 200, '{"result": %s}' % (json.dumps(devices_schema, ))), + MockResponse('get_schema', {'path': '/ncs:devices/device'}, 200, '{"result": %s}' % (json.dumps(device_schema, ))), + MockResponse('exists', {'path': '/ncs:devices/device{ce0}'}, 200, '{"result": {"exists": true}}'), + MockResponse('get_value', {'path': '/ncs:devices/device{ce0}/description'}, 200, '{"result": {"value": "Example Device"}}'), + MockResponse('logout', {}, 200, '{"result": {}}'), + ] + open_url_mock.side_effect = lambda *args, **kwargs: nso_module.mock_call(calls, *args, **kwargs) + + data = nso_module.load_fixture('verify_violation_data.json') + set_module_args({ + 'username': 'user', 'password': 'password', + 'url': 'http://localhost:8080/jsonrpc', 'data': data, + 'validate_certs': False + }) + self.execute_module(changed=False) + + self.assertEqual(0, len(calls)) diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/utils.py b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/utils.py new file mode 100644 index 00000000..b14efe26 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/utils.py @@ -0,0 +1,50 @@ +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +import json + +from ansible_collections.cisco.nso.tests.unit.compat import unittest +from ansible_collections.cisco.nso.tests.unit.compat.mock import patch +from ansible.module_utils import basic +from ansible.module_utils._text import to_bytes + + +def set_module_args(args): + if '_ansible_remote_tmp' not in args: + args['_ansible_remote_tmp'] = '/tmp' + if '_ansible_keep_remote_files' not in args: + args['_ansible_keep_remote_files'] = False + + args = json.dumps({'ANSIBLE_MODULE_ARGS': args}) + basic._ANSIBLE_ARGS = to_bytes(args) + + +class AnsibleExitJson(Exception): + pass + + +class AnsibleFailJson(Exception): + pass + + +def exit_json(*args, **kwargs): + if 'changed' not in kwargs: + kwargs['changed'] = False + raise AnsibleExitJson(kwargs) + + +def fail_json(*args, **kwargs): + kwargs['failed'] = True + raise AnsibleFailJson(kwargs) + + +class ModuleTestCase(unittest.TestCase): + + def setUp(self): + self.mock_module = patch.multiple(basic.AnsibleModule, exit_json=exit_json, fail_json=fail_json) + self.mock_module.start() + self.mock_sleep = patch('time.sleep') + self.mock_sleep.start() + set_module_args({}) + self.addCleanup(self.mock_module.stop) + self.addCleanup(self.mock_sleep.stop) diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/requirements.txt b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/requirements.txt new file mode 100644 index 00000000..46fbfa46 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/requirements.txt @@ -0,0 +1 @@ +unittest2 ; python_version < '2.7' |