diff options
Diffstat (limited to 'collections-debian-merged/ansible_collections/servicenow')
31 files changed, 3281 insertions, 0 deletions
diff --git a/collections-debian-merged/ansible_collections/servicenow/servicenow/.github/workflows/ansible-test.yml b/collections-debian-merged/ansible_collections/servicenow/servicenow/.github/workflows/ansible-test.yml new file mode 100644 index 00000000..70a87e12 --- /dev/null +++ b/collections-debian-merged/ansible_collections/servicenow/servicenow/.github/workflows/ansible-test.yml @@ -0,0 +1,51 @@ +name: CI +on: +# Run CI against all pushes (direct commits) and Pull Requests +- push +- pull_request + +jobs: + +### +# Sanity tests (REQUIRED) +# +# https://docs.ansible.com/ansible/latest/dev_guide/testing_sanity.html + + sanity: + name: Sanity (Ⓐ${{ matrix.ansible }}+py${{ matrix.python }}) + 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 + python: + - 2.7 + - 3.7 + - 3.8 + exclude: + - python: 3.8 # blocked by ansible/ansible#70155 + runs-on: ubuntu-latest + steps: + + - name: Check out code + uses: actions/checkout@v1 + with: + path: ansible_collections/servicenow/servicenow + + - name: Set up Python ${{ matrix.ansible }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python }} + + # 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. + # Explicity specify the version of Python we want to test + - name: Run sanity tests + run: ansible-test sanity --docker -v --color --python ${{ matrix.python }} diff --git a/collections-debian-merged/ansible_collections/servicenow/servicenow/.github/workflows/galaxy-release.yml b/collections-debian-merged/ansible_collections/servicenow/servicenow/.github/workflows/galaxy-release.yml new file mode 100644 index 00000000..64614c50 --- /dev/null +++ b/collections-debian-merged/ansible_collections/servicenow/servicenow/.github/workflows/galaxy-release.yml @@ -0,0 +1,31 @@ +--- +name: galaxy-release +on: + release: + types: + - published + +jobs: + release: + runs-on: ubuntu-latest + env: + ANSIBLE_FORCE_COLOR: 1 + steps: + - name: Check out code + uses: actions/checkout@v1 + + - name: Set up Python 3.8 + uses: actions/setup-python@v1 + with: + python-version: 3.8 + + - name: Install ansible-base + run: pip install ansible + + - name: Publish to galaxy + run: ansible-playbook release.yml + -e namespace=${{ github.repository_owner }} + -e github_tag=${{ github.ref }} + -e api_key=${{ secrets.ANSIBLE_GALAXY_APIKEY }} + -e collection_repo=https://github.com/${{ github.repository }} + --skip-tags=install,cleanup diff --git a/collections-debian-merged/ansible_collections/servicenow/servicenow/.gitignore b/collections-debian-merged/ansible_collections/servicenow/servicenow/.gitignore new file mode 100644 index 00000000..336766e0 --- /dev/null +++ b/collections-debian-merged/ansible_collections/servicenow/servicenow/.gitignore @@ -0,0 +1,394 @@ +# Mac Junk +.DS_Store + +#Ansible artifacts +tests/output +*.tar.gz +galaxy.yml + +# 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 diff --git a/collections-debian-merged/ansible_collections/servicenow/servicenow/CHANGELOG.rst b/collections-debian-merged/ansible_collections/servicenow/servicenow/CHANGELOG.rst new file mode 100644 index 00000000..e500b0de --- /dev/null +++ b/collections-debian-merged/ansible_collections/servicenow/servicenow/CHANGELOG.rst @@ -0,0 +1,36 @@ +=================================== +Servicenow.Servicenow Release Notes +=================================== + +.. contents:: Topics + + +v1.0.4 +====== + +Major Changes +------------- + +- add new tests (find with no result, search many) +- add related tests +- add support for ServiceNOW table api display_value exclude_reference_link and suppress_pagination_header +- use new API for pysnow >=0.6.0 + +v1.0.3 +====== + +Release Summary +--------------- + +use consistent auth parameters across plugins and modules + +Minor Changes +------------- + +- adds the ability to use `SN_INSTANCE` (ex. `dev61775`) or `SN_HOST` (ex. `dev61775.service-now.com`) with the inventory plugin. + +Bugfixes +-------- + +- fix inventory plugin transforming hostnames unnecessarily +- fix malformed documentation on docs.ansible.com diff --git a/collections-debian-merged/ansible_collections/servicenow/servicenow/FILES.json b/collections-debian-merged/ansible_collections/servicenow/servicenow/FILES.json new file mode 100644 index 00000000..072f16f4 --- /dev/null +++ b/collections-debian-merged/ansible_collections/servicenow/servicenow/FILES.json @@ -0,0 +1,320 @@ +{ + "files": [ + { + "name": ".", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "config", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "config/now.yml.sample", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "606cea64ee0670f91c9f9c4d5f0bb96a6d78e649c97339ea8397194e2ac630d5", + "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/galaxy-release.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "bc82e07b7d94027d17753d366917193d3b75f09ba96b77662c5c8ae08584b50d", + "format": 1 + }, + { + "name": ".github/workflows/ansible-test.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "7edfb7837997796db09c6755dfc60bdbbb3371e6b6af269e344d6e5173053bfe", + "format": 1 + }, + { + "name": "CHANGELOG.rst", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "5787d890fecad4674e224601c31222f0389e3bb907d6c74783692795eca207aa", + "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": "docs", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "docs/templates", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "docs/templates/docs.md.j2", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "8431b9f9430d6d0c1154dde567e2406cfe0e2526449740cc7014f7b2df3c8fbb", + "format": 1 + }, + { + "name": "docs/inventory.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "4fa69a805fd91aafea36f2672677d3319c9c6a25b39e2bd03684172bb8c2f6fc", + "format": 1 + }, + { + "name": "docs/snow_record_find.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "03197238ab13b8a897e5d7612f08f7ae55ad1cedf7a6507758a1a6b07cd4349e", + "format": 1 + }, + { + "name": "docs/snow_record.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "07643b41e054a048c7ac8cfeb6fc72bfa5e8c60065a8f2b7d961423c6dbcc2d5", + "format": 1 + }, + { + "name": "docs/create_docs.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e7e7588a0b59e2e5b7512a19ec6133fc96bf5aac68b87eb869b225b6cb767364", + "format": 1 + }, + { + "name": "tests", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/now.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "3914964e05a01859050ec3a5062cd6609aa381228de274a191656bb6cd146b63", + "format": 1 + }, + { + "name": "tests/module_test.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a2aecb71b1e36d9d03aeaab570664c9b0f0a98c192caef294d35f2b2865ade8a", + "format": 1 + }, + { + "name": "tests/enhanced.now.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ee1ac7151369516c6016ccb9b66ea6574ee3c71e34d8f4269c9cffc1cab20ebe", + "format": 1 + }, + { + "name": "tests/network.enhanced.now.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b761770cbf0844ef603fd11d7b9b4da06dacc15416a41630c12d5d8ca384216a", + "format": 1 + }, + { + "name": "tests/module_test_cmdb_ci_server.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "f16a3e9b0e7eee38917c9681bd471dea9d11e15f275bd0ce6deb7f6fd37cb199", + "format": 1 + }, + { + "name": "update_sets", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "update_sets/ansible_enhanced_inventory.xml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "7ba14302626a267df368fad993c7b784d9b8398a9091a54192902c34afd18b61", + "format": 1 + }, + { + "name": "update_sets/README.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "d047f003c705cdb793cad679fe0da9fcca63a6d326d570172525aac134c8df54", + "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/service_now.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "df633dfdeca0822cc25d6d9e4ed85ce84e0cf725cd0b1eb35c77437ed925c466", + "format": 1 + }, + { + "name": "plugins/inventory", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "plugins/inventory/now.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "78e9d17cd73456a7951736dafdd79705f3260e02e2d9e85d64b35565fc11f306", + "format": 1 + }, + { + "name": "plugins/module_utils", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "plugins/module_utils/service_now.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "448aa9dd05b9e927890c199bddd3ea85aa59c30468d28a817151a6efb58979f3", + "format": 1 + }, + { + "name": "plugins/modules", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "plugins/modules/snow_record_find.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "5cc0f5513b09ab0746ad83ef419449c4399b4dbea118378ccdff18f85dd44f1a", + "format": 1 + }, + { + "name": "plugins/modules/snow_record.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "31c6dbd741d69da49c2d958a38b9121691f91ff14adafc0a7d2e2afffc04d7d6", + "format": 1 + }, + { + "name": "README.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "830b90abbfe0cf65c38f0b85713f55313e799ff39a2f566b7cce3e1f6f7d4bdf", + "format": 1 + }, + { + "name": ".gitignore", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "afd19f3a546e4f7c923914f5f9e7c0fb0c17680a00b63f73b2720fa56ec9e7b4", + "format": 1 + }, + { + "name": "changelogs", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "changelogs/.plugin-cache.yaml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ee7076ee32a338d6b4f79b738fd41d93c4a74816e21c39d02d8193670a8fd47a", + "format": 1 + }, + { + "name": "changelogs/fragments", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "changelogs/fragments/.keep", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "format": 1 + }, + { + "name": "changelogs/config.yaml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b6f36b2c363e4e2764cecdbfeee2be02fa4d9704b0d132d426918358f708a2bf", + "format": 1 + }, + { + "name": "changelogs/changelog.yaml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "6367c874144d392e40c44eee71b4f6d235e7bee24bc82e89c271b4160cfe1214", + "format": 1 + }, + { + "name": "requirements.txt", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "447a636d781f1d0dc043a0e3eafdc9a73fad67e68e6bd5a9ad6ebf003ae365e6", + "format": 1 + } + ], + "format": 1 +}
\ No newline at end of file diff --git a/collections-debian-merged/ansible_collections/servicenow/servicenow/MANIFEST.json b/collections-debian-merged/ansible_collections/servicenow/servicenow/MANIFEST.json new file mode 100644 index 00000000..fbaff245 --- /dev/null +++ b/collections-debian-merged/ansible_collections/servicenow/servicenow/MANIFEST.json @@ -0,0 +1,40 @@ +{ + "collection_info": { + "namespace": "servicenow", + "name": "servicenow", + "version": "1.0.4", + "authors": [ + "Paul Knight <paul.knight@delaware.gov>", + "Tim Rightnour <thegarbledone@gmail.com>", + "Will Tome (@willtome)", + "Alex Mittell (@alex_mittell)" + ], + "readme": "README.md", + "tags": [ + "preview", + "servicenow", + "snow", + "collection", + "inventory", + "plugin" + ], + "description": "The Service Now modules previously packaged as part of Ansible, now in a Collection distributed via Ansible Galaxy. snow_record creates, updates or deletes a record in a specified table in the Service Now instance. snow_record_find retrieves one or more records based on the supplied query. ServiceNow Inventory Plugin for using ServiceNow CMDB as a dynamic inventory source.\n", + "license": [ + "GPL-3.0-or-later" + ], + "license_file": null, + "dependencies": {}, + "repository": "https://github.com/ServiceNowITOM/servicenow-ansible", + "documentation": "https://github.com/ServiceNowITOM/servicenow-ansible/wiki", + "homepage": "https://github.com/ServiceNowITOM/servicenow-ansible", + "issues": "https://github.com/ServiceNowITOM/servicenow-ansible/issues" + }, + "file_manifest_file": { + "name": "FILES.json", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e0f0bc81456475e1de90a90122535407bfe446587c0cae9e9e20bfe7308a86cf", + "format": 1 + }, + "format": 1 +}
\ No newline at end of file diff --git a/collections-debian-merged/ansible_collections/servicenow/servicenow/README.md b/collections-debian-merged/ansible_collections/servicenow/servicenow/README.md new file mode 100644 index 00000000..071d4b08 --- /dev/null +++ b/collections-debian-merged/ansible_collections/servicenow/servicenow/README.md @@ -0,0 +1,93 @@ +![CI](https://github.com/ServiceNowITOM/servicenow-ansible/workflows/CI/badge.svg) + +# Ansible Collection for ServiceNow +This collection provides a series of Ansible modules, roles, and plugins for interacting with [ServiceNow](https://servicenow.com) + +## Requirements + - ansible version >= 2.9 + - pysnow + - netaddr + +## Installation + +To install ServiceNow collection hosted in Galaxy: + +```bash +ansible-galaxy collection install servicenow.servicenow +``` + +To upgrade to the latest version of ServiceNow collection: + +```bash +ansible-galaxy collection install servicenow.servicenow --force +``` +## Usage + +### Playbooks + +To use a module from the ServiceNow collection, please reference the fill namespace, collection name, and module name that you want to use: + +```yaml +--- +- name: Using ServiceNow Collection + hosts: localhost + gather_facts: no + + tasks: + - name: Create an incident + servicenow.servicenow.snow_record: + username: ansible_test + password: my_password + instance: dev99999 + state: present + data: + short_description: "This is a test incident opened by Ansible" + severity: 3 + priority: 2 +``` + +Or you can add full namespace and collection name in the `collections` section: + +```yaml +--- +- name: Using ServiceNow Collection + hosts: localhost + gather_facts: no + collections: + - servicenow.servicenow + + tasks: + - name: Create an incident + snow_record: + username: ansible_test + password: my_password + instance: dev99999 + state: present + data: + short_description: "This is a test incident opened by Ansible" + severity: 3 + priority: 2 +``` + +### Roles + +For existing Ansible roles, please also reference the full namespace, collection name, and modules name which used in tasks instead of just modules name. + +## Resource Included + +### Modules +- [snow_record](docs/snow_record.md) - Creates, deletes and updates a single record in ServiceNow. +- [snow_record_find](docs/snow_record_find.md) - Gets multiple records from a specified table from ServiceNow based on a query dictionary. + +### Plugins +- [now](docs/inventory.md) - ServiceNow Inventory Plugin + +## Contributing + +There are many ways in which you can participate in the project, for example: + +- Submit bugs and feature requests, and help us verify as they are checked in +- Review source code changes +- Review the documentation and make pull requests for anything from typos to new content + +Special thanks to Tim Rightnour (@garbled1) for the original version of ServiceNow modules in Ansible Core. diff --git a/collections-debian-merged/ansible_collections/servicenow/servicenow/changelogs/.plugin-cache.yaml b/collections-debian-merged/ansible_collections/servicenow/servicenow/changelogs/.plugin-cache.yaml new file mode 100644 index 00000000..fbb1bf38 --- /dev/null +++ b/collections-debian-merged/ansible_collections/servicenow/servicenow/changelogs/.plugin-cache.yaml @@ -0,0 +1,29 @@ +plugins: + become: {} + cache: {} + callback: {} + cliconf: {} + connection: {} + httpapi: {} + inventory: + now: + description: ServiceNow Inventory Plugin + name: now + version_added: '2.10' + lookup: {} + module: + snow_record: + description: Manage records in ServiceNow + name: snow_record + namespace: '' + version_added: null + snow_record_find: + description: Search for multiple records from ServiceNow + name: snow_record_find + namespace: '' + version_added: null + netconf: {} + shell: {} + strategy: {} + vars: {} +version: 1.0.4 diff --git a/collections-debian-merged/ansible_collections/servicenow/servicenow/changelogs/changelog.yaml b/collections-debian-merged/ansible_collections/servicenow/servicenow/changelogs/changelog.yaml new file mode 100644 index 00000000..cd39a5b6 --- /dev/null +++ b/collections-debian-merged/ansible_collections/servicenow/servicenow/changelogs/changelog.yaml @@ -0,0 +1,29 @@ +ancestor: null +releases: + 1.0.3: + changes: + bugfixes: + - fix inventory plugin transforming hostnames unnecessarily + - fix malformed documentation on docs.ansible.com + minor_changes: + - adds the ability to use `SN_INSTANCE` (ex. `dev61775`) or `SN_HOST` (ex. `dev61775.service-now.com`) + with the inventory plugin. + release_summary: use consistent auth parameters across plugins and modules + fragments: + - 1.0.3_release_summary.yml + - 17_auth_consistency.yml + - 22_hostnames.yml + - 29_documentation.yml + release_date: '2020-10-30' + 1.0.4: + changes: + major_changes: + - add new tests (find with no result, search many) + - add related tests + - add support for ServiceNOW table api display_value exclude_reference_link + and suppress_pagination_header + - use new API for pysnow >=0.6.0 + fragments: + - 34_pysnow_0.6.yml + - 35_add_new_parameters.yml + release_date: '2021-02-03' diff --git a/collections-debian-merged/ansible_collections/servicenow/servicenow/changelogs/config.yaml b/collections-debian-merged/ansible_collections/servicenow/servicenow/changelogs/config.yaml new file mode 100644 index 00000000..408156ea --- /dev/null +++ b/collections-debian-merged/ansible_collections/servicenow/servicenow/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: false +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: Servicenow.Servicenow +trivial_section_name: trivial +use_fqcn: true diff --git a/collections-debian-merged/ansible_collections/servicenow/servicenow/changelogs/fragments/.keep b/collections-debian-merged/ansible_collections/servicenow/servicenow/changelogs/fragments/.keep new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/collections-debian-merged/ansible_collections/servicenow/servicenow/changelogs/fragments/.keep diff --git a/collections-debian-merged/ansible_collections/servicenow/servicenow/config/now.yml.sample b/collections-debian-merged/ansible_collections/servicenow/servicenow/config/now.yml.sample new file mode 100644 index 00000000..103b2df9 --- /dev/null +++ b/collections-debian-merged/ansible_collections/servicenow/servicenow/config/now.yml.sample @@ -0,0 +1,5 @@ +plugin: servicenow.servicenow.now +instance: demo.service-now.com +username: admin +password: password +cache: True diff --git a/collections-debian-merged/ansible_collections/servicenow/servicenow/docs/create_docs.yml b/collections-debian-merged/ansible_collections/servicenow/servicenow/docs/create_docs.yml new file mode 100644 index 00000000..586137a9 --- /dev/null +++ b/collections-debian-merged/ansible_collections/servicenow/servicenow/docs/create_docs.yml @@ -0,0 +1,28 @@ +--- +- hosts: localhost + gather_facts: no + + tasks: + - set_fact: + docs: "{{ lookup('file', '../plugins/inventory/now.py') | regex_search(\"(?<=DOCUMENTATION\\s=\\s''')((.|\\n)*?)(?=''')\") | from_yaml}}" + examples: "{{ lookup('file', '../plugins/inventory/now.py') | regex_search(\"(?<=EXAMPLES\\s=\\s''')((.|\\n)*?)(?=''')\") }}" + + - template: + src: ./templates/docs.md.j2 + dest: ./inventory.md + + - set_fact: + docs: "{{ lookup('file', '../plugins/modules/snow_record.py') | regex_search(\"(?<=DOCUMENTATION\\s=\\s''')((.|\\n)*?)(?=''')\") | from_yaml}}" + examples: "{{ lookup('file', '../plugins/modules/snow_record.py') | regex_search(\"(?<=EXAMPLES\\s=\\s''')((.|\\n)*?)(?=''')\") }}" + + - template: + src: ./templates/docs.md.j2 + dest: ./snow_record.md + + - set_fact: + docs: "{{ lookup('file', '../plugins/modules/snow_record_find.py') | regex_search(\"(?<=DOCUMENTATION\\s=\\s''')((.|\\n)*?)(?=''')\") | from_yaml}}" + examples: "{{ lookup('file', '../plugins/modules/snow_record_find.py') | regex_search(\"(?<=EXAMPLES\\s=\\s''')((.|\\n)*?)(?=''')\") }}" + + - template: + src: ./templates/docs.md.j2 + dest: ./snow_record_find.md
\ No newline at end of file diff --git a/collections-debian-merged/ansible_collections/servicenow/servicenow/docs/inventory.md b/collections-debian-merged/ansible_collections/servicenow/servicenow/docs/inventory.md new file mode 100644 index 00000000..64cc4924 --- /dev/null +++ b/collections-debian-merged/ansible_collections/servicenow/servicenow/docs/inventory.md @@ -0,0 +1,170 @@ +servicenow.servicenow.now - ServiceNow Inventory Plugin +==================================== +- [Synopsis](Synopsis) +- [Requirements](Requirements) +- [Parameters](Parameters) +- [Examples](Examples) + +## Synopsis +- ServiceNow Inventory plugin + +## Requirements +- requests +- netaddr + +## Parameters + +<table> +<tr> +<th> Parameter </th> +<th> Choices/Defaults </th> +<th> Configuration </th> +<th> Comments </th> +</tr> +<tr> +<td><b>username</b></br> +</td> +<td></td> +<td><b>env:</b><br> +- name: SN_USERNAME +</td> +<td> Name of user for connection to ServiceNow. If the value is not specified, the value of environment variable C(SN_USERNAME) will be used instead. </td> +</tr> +<tr> +<td><b>plugin</b></br> +<p style="color:red;font-size:75%">required</p></td> +<td><b>Choices:</b><br> +- servicenow.servicenow.now +</td> +<td></td> +<td> The name of the ServiceNow Inventory Plugin, this should always be 'servicenow.servicenow.now'. </td> +</tr> +<tr> +<td><b>fields</b></br> +</td> +<td><b>Default:</b><br> +ip_address,fqdn,host_name,sys_class_name,name</td> +<td></td> +<td> Comma seperated string providing additional table columns to add as host vars to each inventory host. </td> +</tr> +<tr> +<td><b>instance</b></br> +</td> +<td></td> +<td><b>env:</b><br> +- name: SN_INSTANCE +</td> +<td> The ServiceNow instance name, without the domain, service-now.com. If the value is not specified in the task, the value of environment variable C(SN_INSTANCE) will be used instead. </td> +</tr> +<tr> +<td><b>host</b></br> +</td> +<td></td> +<td><b>env:</b><br> +- name: SN_HOST +</td> +<td> The ServiceNow hostname. This value is FQDN for ServiceNow host. If the value is not specified in the task, the value of environment variable C(SN_HOST) will be used instead. Mutually exclusive with C(instance). </td> +</tr> +<tr> +<td><b>filter_results</b></br> +</td> +<td><b>Default:</b><br> +</td> +<td></td> +<td> Filter results with sysparm_query encoded query string syntax. Complete list of operators available for filters and queries. </td> +</tr> +<tr> +<td><b>proxy</b></br> +</td> +<td><b>Default:</b><br> +</td> +<td></td> +<td> Proxy server to use for requests to ServiceNow. </td> +</tr> +<tr> +<td><b>enhanced</b></br> +</td> +<td><b>Default:</b><br> +False</td> +<td></td> +<td> enable enhanced inventory which provides relationship information from CMDB. Requires installation of Update Set. </td> +</tr> +<tr> +<td><b>selection_order</b></br> +</td> +<td><b>Default:</b><br> +ip_address,fqdn,host_name,name</td> +<td></td> +<td> Comma seperated string providing ability to define selection preference order. </td> +</tr> +<tr> +<td><b>table</b></br> +</td> +<td><b>Default:</b><br> +cmdb_ci_server</td> +<td></td> +<td> The ServiceNow table to query </td> +</tr> +<tr> +<td><b>enhanced_groups</b></br> +</td> +<td><b>Default:</b><br> +True</td> +<td></td> +<td> enable enhanced groups from CMDB relationships. Only used if enhanced is enabled. </td> +</tr> +<tr> +<td><b>password</b></br> +<p style="color:red;font-size:75%">required</p></td> +<td></td> +<td><b>env:</b><br> +- name: SN_PASSWORD +</td> +<td> Password for username. If the value is not specified, the value of environment variable C(SN_PASSWORD) will be used instead. </td> +</tr> +</table> + +## Examples +``` + +plugin: servicenow.servicenow.now +instance: dev89007 +username: admin +password: password +keyed_groups: + - key: sn_sys_class_name | lower + prefix: '' + separator: '' + +plugin: servicenow.servicenow.now +host: servicenow.mydomain.com +username: admin +password: password +fields: [name,host_name,fqdn,ip_address,sys_class_name, install_status, classification,vendor] +keyed_groups: + - key: sn_classification | lower + prefix: 'env' + - key: sn_vendor | lower + prefix: '' + separator: '' + - key: sn_sys_class_name | lower + prefix: '' + separator: '' + - key: sn_install_status | lower + prefix: 'status' + +plugin: servicenow.servicenow.now +instance: dev89007 +username: admin +password: password +fields: + - name + - sys_tags +compose: + sn_tags: sn_sys_tags.replace(" ", "").split(',') + ansible_host: sn_ip_address +keyed_groups: + - key: sn_tags | lower + prefix: 'tag' + +```
\ No newline at end of file diff --git a/collections-debian-merged/ansible_collections/servicenow/servicenow/docs/snow_record.md b/collections-debian-merged/ansible_collections/servicenow/servicenow/docs/snow_record.md new file mode 100644 index 00000000..a9452daf --- /dev/null +++ b/collections-debian-merged/ansible_collections/servicenow/servicenow/docs/snow_record.md @@ -0,0 +1,156 @@ +snow_record - Manage records in ServiceNow +==================================== +- [Synopsis](Synopsis) +- [Requirements](Requirements) +- [Parameters](Parameters) +- [Examples](Examples) + +## Synopsis +- Creates, deletes and updates a single record in ServiceNow. + +## Requirements +- python pysnow (pysnow) + +## Parameters + +<table> +<tr> +<th> Parameter </th> +<th> Choices/Defaults </th> +<th> Configuration </th> +<th> Comments </th> +</tr> +<tr> +<td><b>number</b></br> +</td> +<td></td> +<td></td> +<td> Record number to update. Required for C(state:absent). </td> +</tr> +<tr> +<td><b>state</b></br> +<p style="color:red;font-size:75%">required</p></td> +<td><b>Choices:</b><br> +- present +- absent +</td> +<td></td> +<td> If C(present) is supplied with a C(number) argument, the module will attempt to update the record with the supplied data. If no such record exists, a new one will be created. C(absent) will delete a record. </td> +</tr> +<tr> +<td><b>attachment</b></br> +</td> +<td></td> +<td></td> +<td> Attach a file to the record. </td> +</tr> +<tr> +<td><b>table</b></br> +</td> +<td><b>Default:</b><br> +incident</td> +<td></td> +<td> Table to query for records. </td> +</tr> +<tr> +<td><b>lookup_field</b></br> +</td> +<td><b>Default:</b><br> +number</td> +<td></td> +<td> Changes the field that C(number) uses to find records. </td> +</tr> +<tr> +<td><b>data</b></br> +</td> +<td></td> +<td></td> +<td> key, value pairs of data to load into the record. See Examples. Required for C(state:present). </td> +</tr> +</table> + +## Examples +``` + +- name: Grab a user record + snow_record: + username: ansible_test + password: my_password + instance: dev99999 + state: present + number: 62826bf03710200044e0bfc8bcbe5df1 + table: sys_user + lookup_field: sys_id + +- name: Grab a user record using OAuth + snow_record: + username: ansible_test + password: my_password + client_id: "1234567890abcdef1234567890abcdef" + client_secret: "Password1!" + instance: dev99999 + state: present + number: 62826bf03710200044e0bfc8bcbe5df1 + table: sys_user + lookup_field: sys_id + +- name: Create an incident + snow_record: + username: ansible_test + password: my_password + instance: dev99999 + state: present + data: + short_description: "This is a test incident opened by Ansible" + severity: 3 + priority: 2 + register: new_incident + +- name: Create an incident using host instead of instance + snow_record: + username: ansible_test + password: my_password + host: dev99999.mycustom.domain.com + state: present + data: + short_description: "This is a test incident opened by Ansible" + priority: 2 + +- name: Delete the record we just made + snow_record: + username: admin + password: xxxxxxx + instance: dev99999 + state: absent + number: "{{new_incident['record']['number']}}" + +- name: Delete a non-existant record + snow_record: + username: ansible_test + password: my_password + instance: dev99999 + state: absent + number: 9872354 + failed_when: false + +- name: Update an incident + snow_record: + username: ansible_test + password: my_password + instance: dev99999 + state: present + number: INC0000055 + data: + work_notes : "Been working all day on this thing." + +- name: Attach a file to an incident + snow_record: + username: ansible_test + password: my_password + instance: dev99999 + state: present + number: INC0000055 + attachment: README.md + tags: attach + +```
\ No newline at end of file diff --git a/collections-debian-merged/ansible_collections/servicenow/servicenow/docs/snow_record_find.md b/collections-debian-merged/ansible_collections/servicenow/servicenow/docs/snow_record_find.md new file mode 100644 index 00000000..74eb419a --- /dev/null +++ b/collections-debian-merged/ansible_collections/servicenow/servicenow/docs/snow_record_find.md @@ -0,0 +1,131 @@ +snow_record_find - Search for multiple records from ServiceNow +==================================== +- [Synopsis](Synopsis) +- [Requirements](Requirements) +- [Parameters](Parameters) +- [Examples](Examples) + +## Synopsis +- Gets multiple records from a specified table from ServiceNow based on a query dictionary. + +## Requirements +- python pysnow (pysnow) + +## Parameters + +<table> +<tr> +<th> Parameter </th> +<th> Choices/Defaults </th> +<th> Configuration </th> +<th> Comments </th> +</tr> +<tr> +<td><b>table</b></br> +</td> +<td><b>Default:</b><br> +incident</td> +<td></td> +<td> Table to query for records. </td> +</tr> +<tr> +<td><b>max_records</b></br> +</td> +<td><b>Default:</b><br> +20</td> +<td></td> +<td> Maximum number of records to return. </td> +</tr> +<tr> +<td><b>return_fields</b></br> +</td> +<td></td> +<td></td> +<td> Fields of the record to return in the json. By default, all fields will be returned. </td> +</tr> +<tr> +<td><b>order_by</b></br> +</td> +<td><b>Default:</b><br> +-created_on</td> +<td></td> +<td> Field to sort the results on. Can prefix with "-" or "+" to change descending or ascending sort order. </td> +</tr> +<tr> +<td><b>query</b></br> +<p style="color:red;font-size:75%">required</p></td> +<td></td> +<td></td> +<td> Dict to query for records. </td> +</tr> +</table> + +## Examples +``` + +- name: Search for incident assigned to group, return specific fields + snow_record_find: + username: ansible_test + password: my_password + instance: dev99999 + table: incident + query: + assignment_group: d625dccec0a8016700a222a0f7900d06 + return_fields: + - number + - opened_at + +- name: Search for incident using host instead of instance + snow_record_find: + username: ansible_test + password: my_password + host: dev99999.mycustom.domain.com + table: incident + query: + assignment_group: d625dccec0a8016700a222a0f7900d06 + return_fields: + - number + - opened_at + +- name: Using OAuth, search for incident assigned to group, return specific fields + snow_record_find: + username: ansible_test + password: my_password + client_id: "1234567890abcdef1234567890abcdef" + client_secret: "Password1!" + instance: dev99999 + table: incident + query: + assignment_group: d625dccec0a8016700a222a0f7900d06 + return_fields: + - number + - opened_at + +- name: Find open standard changes with my template + snow_record_find: + username: ansible_test + password: my_password + instance: dev99999 + table: change_request + query: + AND: + equals: + active: "True" + type: "standard" + u_change_stage: "80" + contains: + u_template: "MY-Template" + return_fields: + - sys_id + - number + - sys_created_on + - sys_updated_on + - u_template + - active + - type + - u_change_stage + - sys_created_by + - description + - short_description + +```
\ No newline at end of file diff --git a/collections-debian-merged/ansible_collections/servicenow/servicenow/docs/templates/docs.md.j2 b/collections-debian-merged/ansible_collections/servicenow/servicenow/docs/templates/docs.md.j2 new file mode 100644 index 00000000..03fd3007 --- /dev/null +++ b/collections-debian-merged/ansible_collections/servicenow/servicenow/docs/templates/docs.md.j2 @@ -0,0 +1,38 @@ +{% if docs.name is defined %}{{ docs.name }}{% else %}{{ docs.module }}{% endif %} - {{ docs.short_description }} +==================================== +- [Synopsis](Synopsis) +- [Requirements](Requirements) +- [Parameters](Parameters) +- [Examples](Examples) + +## Synopsis +{{ docs.description | to_nice_yaml}} +## Requirements +{{ docs.requirements | default('') | to_nice_yaml }} +## Parameters + +<table> +<tr> +<th> Parameter </th> +<th> Choices/Defaults </th> +<th> Configuration </th> +<th> Comments </th> +</tr> +{% for option in docs.options %} +<tr> +<td><b>{{ option }}</b></br> +{% if docs.options[option]['required'] is defined and docs.options[option]['required'] %}<p style="color:red;font-size:75%">required</p>{% endif %}</td> +<td>{% if docs.options[option]['choices'] is defined %}<b>Choices:</b><br> +{{ docs.options[option]['choices'] | to_nice_yaml }}{% endif %}{% if docs.options[option]['default'] is defined %}<b>Default:</b><br> +{{ docs.options[option]['default'] }}{% endif %}</td> +<td>{% if docs.options[option]['env'] is defined %}<b>env:</b><br> +{{ docs.options[option]['env'] | to_nice_yaml }}{% endif %}</td> +<td>{% if docs.options[option]['description'] is string %} {{docs.options[option]['description']}} {% else %} {% for line in docs.options[option]['description'] %} {{line}} {% endfor %} {% endif %}</td> +</tr> +{% endfor %} +</table> + +## Examples +``` +{{ examples }} +```
\ No newline at end of file diff --git a/collections-debian-merged/ansible_collections/servicenow/servicenow/meta/runtime.yml b/collections-debian-merged/ansible_collections/servicenow/servicenow/meta/runtime.yml new file mode 100644 index 00000000..1f18fd72 --- /dev/null +++ b/collections-debian-merged/ansible_collections/servicenow/servicenow/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/servicenow/servicenow/plugins/doc_fragments/service_now.py b/collections-debian-merged/ansible_collections/servicenow/servicenow/plugins/doc_fragments/service_now.py new file mode 100644 index 00000000..295af3b4 --- /dev/null +++ b/collections-debian-merged/ansible_collections/servicenow/servicenow/plugins/doc_fragments/service_now.py @@ -0,0 +1,50 @@ +# -*- coding: utf-8 -*- +# Copyright: (c) 2019, Ansible Project +# 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): + # Parameters for Service Now modules + DOCUMENTATION = r''' +options: + instance: + description: + - The ServiceNow instance name, without the domain, service-now.com. + - If the value is not specified in the task, the value of environment variable C(SN_INSTANCE) will be used instead. + required: false + type: str + host: + description: + - The ServiceNow hostname. + - This value is FQDN for ServiceNow host. + - If the value is not specified in the task, the value of environment variable C(SN_HOST) will be used instead. + - Mutually exclusive with C(instance). + type: str + username: + description: + - Name of user for connection to ServiceNow. + - Required whether using Basic or OAuth authentication. + - If the value is not specified in the task, the value of environment variable C(SN_USERNAME) will be used instead. + required: false + type: str + password: + description: + - Password for username. + - Required whether using Basic or OAuth authentication. + - If the value is not specified in the task, the value of environment variable C(SN_PASSWORD) will be used instead. + required: false + type: str + client_id: + description: + - Client ID generated by ServiceNow. + required: false + type: str + client_secret: + description: + - Client Secret associated with client id. + required: false + type: str +''' diff --git a/collections-debian-merged/ansible_collections/servicenow/servicenow/plugins/inventory/now.py b/collections-debian-merged/ansible_collections/servicenow/servicenow/plugins/inventory/now.py new file mode 100644 index 00000000..b3f28975 --- /dev/null +++ b/collections-debian-merged/ansible_collections/servicenow/servicenow/plugins/inventory/now.py @@ -0,0 +1,316 @@ +# +# Copyright: (c), Ansible Project +# +# 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 + +DOCUMENTATION = r''' + name: servicenow.servicenow.now + plugin_type: inventory + author: + - Will Tome (@willtome) + - Alex Mittell (@alex_mittell) + short_description: ServiceNow Inventory Plugin + version_added: "2.10" + description: + - ServiceNow Inventory plugin. + extends_documentation_fragment: + - constructed + - inventory_cache + requirements: + - requests + options: + plugin: + description: The name of the ServiceNow Inventory Plugin, this should always be 'servicenow.servicenow.now'. + required: True + choices: ['servicenow.servicenow.now'] + instance: + description: + - The ServiceNow instance name, without the domain, service-now.com. + - If the value is not specified in the task, the value of environment variable C(SN_INSTANCE) will be used instead. + required: false + type: str + env: + - name: SN_INSTANCE + host: + description: + - The ServiceNow hostname. + - This value is FQDN for ServiceNow host. + - If the value is not specified in the task, the value of environment variable C(SN_HOST) will be used instead. + - Mutually exclusive with C(instance). + type: str + required: false + env: + - name: SN_HOST + username: + description: + - Name of user for connection to ServiceNow. + - If the value is not specified, the value of environment variable C(SN_USERNAME) will be used instead. + required: false + type: str + env: + - name: SN_USERNAME + password: + description: + - Password for username. + - If the value is not specified, the value of environment variable C(SN_PASSWORD) will be used instead. + required: true + type: str + env: + - name: SN_PASSWORD + table: + description: The ServiceNow table to query. + type: string + default: cmdb_ci_server + fields: + description: Comma seperated string providing additional table columns to add as host vars to each inventory host. + type: list + default: 'ip_address,fqdn,host_name,sys_class_name,name' + selection_order: + description: Comma seperated string providing ability to define selection preference order. + type: list + default: 'ip_address,fqdn,host_name,name' + filter_results: + description: Filter results with sysparm_query encoded query string syntax. Complete list of operators available for filters and queries. + type: string + default: '' + proxy: + description: Proxy server to use for requests to ServiceNow. + type: string + default: '' + enhanced: + description: + - Enable enhanced inventory which provides relationship information from CMDB. + - Requires installation of Update Set located in update_sets directory. + type: bool + default: False + enhanced_groups: + description: enable enhanced groups from CMDB relationships. Only used if enhanced is enabled. + type: bool + default: True + +''' + +EXAMPLES = r''' +# Simple Inventory Plugin example +plugin: servicenow.servicenow.now +instance: dev89007 +username: admin +password: password +keyed_groups: + - key: sn_sys_class_name | lower + prefix: '' + separator: '' + +# Using Keyed Groups +plugin: servicenow.servicenow.now +host: servicenow.mydomain.com +username: admin +password: password +fields: [name,host_name,fqdn,ip_address,sys_class_name, install_status, classification,vendor] +keyed_groups: + - key: sn_classification | lower + prefix: 'env' + - key: sn_vendor | lower + prefix: '' + separator: '' + - key: sn_sys_class_name | lower + prefix: '' + separator: '' + - key: sn_install_status | lower + prefix: 'status' + +# Compose hostvars +plugin: servicenow.servicenow.now +instance: dev89007 +username: admin +password: password +fields: + - name + - sys_tags +compose: + sn_tags: sn_sys_tags.replace(" ", "").split(',') + ansible_host: sn_ip_address +keyed_groups: + - key: sn_tags | lower + prefix: 'tag' +''' + +import netaddr +try: + import requests + HAS_REQUESTS = True +except ImportError: + HAS_REQUESTS = False + +from ansible.errors import AnsibleError, AnsibleParserError +from ansible.plugins.inventory import BaseInventoryPlugin, Constructable, Cacheable, to_safe_group_name + + +class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable): + + NAME = 'servicenow.servicenow.now' + + def verify_file(self, path): + valid = False + if super(InventoryModule, self).verify_file(path): + if path.endswith(('now.yaml', 'now.yml')): + valid = True + else: + self.display.vvv( + 'Skipping due to inventory source not ending in "now.yaml" nor "now.yml"') + return valid + + def invoke(self, verb, path, data): + auth = requests.auth.HTTPBasicAuth(self.get_option('username'), + self.get_option('password')) + headers = { + "Accept": "application/json", + "Content-Type": "application/json", + } + proxy = self.get_option('proxy') + + if self.get_option('instance'): + fqdn = "%s.service-now.com" % (self.get_option('instance')) + elif self.get_option('host'): + fqdn = self.get_option('host') + else: + raise AnsibleError("instance or host must be defined") + + # build url + self.url = "https://%s/%s" % (fqdn, path) + url = self.url + self.display.vvv("Connecting to...%s" % url) + results = [] + + if not self.update_cache: + try: + results = self._cache[self.cache_key][self.url] + except KeyError: + pass + + if not results: + if self.cache_key not in self._cache: + self._cache[self.cache_key] = {self.url: ''} + + session = requests.Session() + + while url: + # perform REST operation, accumulating page results + response = session.get(url, + auth=auth, + headers=headers, + proxies={ + 'http': proxy, + 'https': proxy + }) + if response.status_code == 400 and self.get_option('enhanced'): + raise AnsibleError("http error (%s): %s. Have you installed the enhanced inventory update set on your instance?" % + (response.status_code, response.text)) + elif response.status_code != 200: + raise AnsibleError("http error (%s): %s" % + (response.status_code, response.text)) + results += response.json()['result'] + next_link = response.links.get('next', {}) + url = next_link.get('url', None) + + self._cache[self.cache_key] = {self.url: results} + + results = {'result': results} + return results + + def parse(self, inventory, loader, path, + cache=True): # Plugin interface (2) + super(InventoryModule, self).parse(inventory, loader, path) + + if not HAS_REQUESTS: + raise AnsibleParserError( + 'Please install "requests" Python module as this is required' + ' for ServiceNow dynamic inventory plugin.') + + self._read_config_data(path) + self.cache_key = self.get_cache_key(path) + + self.use_cache = self.get_option('cache') and cache + self.update_cache = self.get_option('cache') and not cache + + selection = self.get_option('selection_order') + fields = self.get_option('fields') + table = self.get_option('table') + filter_results = self.get_option('filter_results') + + options = "?sysparm_exclude_reference_link=true&sysparm_display_value=true" + + enhanced = self.get_option('enhanced') + enhanced_groups = False + + if enhanced: + path = '/api/snc/ansible_inventory' + options + \ + "&sysparm_fields=" + ','.join(fields) + \ + "&sysparm_query=" + filter_results + \ + "&table=" + table + enhanced_groups = self.get_option('enhanced_groups') + else: + path = '/api/now/table/' + table + options + \ + "&sysparm_fields=" + ','.join(fields) + \ + "&sysparm_query=" + filter_results + + content = self.invoke('GET', path, None) + strict = self.get_option('strict') + + for record in content['result']: + + target = None + + # select name for host + for k in selection: + if k in record: + if record[k] != '': + target = record[k] + if target is not None: + break + + if target is None: + continue + + # add host to inventory + host_name = self.inventory.add_host(target) + + # set variables for host + for k in record.keys(): + self.inventory.set_variable(host_name, 'sn_%s' % k, record[k]) + + # add relationship based groups + if enhanced and enhanced_groups: + for item in record['child_relationships']: + ci = to_safe_group_name(item['ci']) + ci_rel_type = to_safe_group_name( + item['ci_rel_type'].split('__')[0]) + ci_type = to_safe_group_name(item['ci_type']) + if ci != '' and ci_rel_type != '' and ci_type != '': + child_group = "%s_%s" % (ci, ci_rel_type) + self.inventory.add_group(child_group) + self.inventory.add_child(child_group, host_name) + + for item in record['parent_relationships']: + ci = to_safe_group_name(item['ci']) + ci_rel_type = to_safe_group_name( + item['ci_rel_type'].split('__')[-1]) + ci_type = to_safe_group_name(item['ci_type']) + + if ci != '' and ci_rel_type != '' and ci_type != '': + child_group = "%s_%s" % (ci, ci_rel_type) + self.inventory.add_group(child_group) + self.inventory.add_child(child_group, host_name) + + self._set_composite_vars( + self.get_option('compose'), + self.inventory.get_host(host_name).get_vars(), host_name, + strict) + + self._add_host_to_composed_groups(self.get_option('groups'), + dict(), host_name, strict) + self._add_host_to_keyed_groups(self.get_option('keyed_groups'), + dict(), host_name, strict) diff --git a/collections-debian-merged/ansible_collections/servicenow/servicenow/plugins/module_utils/service_now.py b/collections-debian-merged/ansible_collections/servicenow/servicenow/plugins/module_utils/service_now.py new file mode 100644 index 00000000..a3caa867 --- /dev/null +++ b/collections-debian-merged/ansible_collections/servicenow/servicenow/plugins/module_utils/service_now.py @@ -0,0 +1,99 @@ +# -*- coding: utf-8 -*- +# Copyright: (c) 2019, Ansible Project +# Copyright: (c) 2017, Tim Rightnour <thegarbledone@gmail.com> +# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +import traceback +from ansible.module_utils.basic import env_fallback, missing_required_lib + +# Pull in pysnow +HAS_PYSNOW = False +PYSNOW_IMP_ERR = None +try: + import pysnow + HAS_PYSNOW = True +except ImportError: + PYSNOW_IMP_ERR = traceback.format_exc() + + +class ServiceNowClient(object): + def __init__(self, module): + """ + Constructor + """ + if not HAS_PYSNOW: + module.fail_json(msg=missing_required_lib('pysnow'), exception=PYSNOW_IMP_ERR) + + self.module = module + self.params = module.params + self.client_id = self.params['client_id'] + self.client_secret = self.params['client_secret'] + self.username = self.params['username'] + self.password = self.params['password'] + self.instance = self.params['instance'] + self.host = self.params['host'] + self.session = {'token': None} + self.conn = None + + def login(self): + result = dict( + changed=False + ) + + if self.params['client_id'] is not None: + try: + self.conn = pysnow.OAuthClient(client_id=self.client_id, + client_secret=self.client_secret, + token_updater=self.updater, + instance=self.instance, + host=self.host) + except Exception as detail: + self.module.fail_json(msg='Could not connect to ServiceNow: {0}'.format(str(detail)), **result) + if not self.session['token']: + # No previous token exists, Generate new. + try: + self.session['token'] = self.conn.generate_token(self.username, self.password) + except pysnow.exceptions.TokenCreateError as detail: + self.module.fail_json(msg='Unable to generate a new token: {0}'.format(str(detail)), **result) + + self.conn.set_token(self.session['token']) + elif self.username is not None: + try: + self.conn = pysnow.Client(instance=self.instance, + host=self.host, + user=self.username, + password=self.password) + except Exception as detail: + self.module.fail_json(msg='Could not connect to ServiceNow: {0}'.format(str(detail)), **result) + else: + snow_error = "Must specify username/password. Also client_id/client_secret if using OAuth." + self.module.fail_json(msg=snow_error, **result) + + def updater(self, new_token): + self.session['token'] = new_token + self.conn = pysnow.OAuthClient(client_id=self.client_id, + client_secret=self.client_secret, + token_updater=self.updater, + instance=self.instance, + host=self.host) + try: + self.conn.set_token(self.session['token']) + except pysnow.exceptions.MissingToken: + snow_error = "Token is missing" + self.module.fail_json(msg=snow_error) + except Exception as detail: + self.module.fail_json(msg='Could not refresh token: {0}'.format(str(detail))) + + @staticmethod + def snow_argument_spec(): + return dict( + instance=dict(type='str', required=False, fallback=(env_fallback, ['SN_INSTANCE'])), + username=dict(type='str', required=False, fallback=(env_fallback, ['SN_USERNAME'])), + host=dict(type='str', required=False, fallback=(env_fallback, ['SN_HOST'])), + password=dict(type='str', required=False, no_log=True, fallback=(env_fallback, ['SN_PASSWORD'])), + client_id=dict(type='str', no_log=True), + client_secret=dict(type='str', no_log=True), + ) diff --git a/collections-debian-merged/ansible_collections/servicenow/servicenow/plugins/modules/snow_record.py b/collections-debian-merged/ansible_collections/servicenow/servicenow/plugins/modules/snow_record.py new file mode 100644 index 00000000..6d4f7ce2 --- /dev/null +++ b/collections-debian-merged/ansible_collections/servicenow/servicenow/plugins/modules/snow_record.py @@ -0,0 +1,387 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2017, Tim Rightnour <thegarbledone@gmail.com> +# 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 + + +DOCUMENTATION = r''' +--- +module: snow_record +short_description: Manage records in ServiceNow +description: + - Creates, deletes and updates a single record in ServiceNow. +options: + table: + description: + - Table to query for records. + required: false + default: incident + type: str + state: + description: + - If C(present) is supplied with a C(number) argument, the module will attempt to update the record with the supplied data. + - If no such record exists, a new one will be created. + - C(absent) will delete a record. + choices: [ present, absent ] + required: true + type: str + data: + description: + - key, value pairs of data to load into the record. See Examples. + - Required for C(state:present). + type: dict + number: + description: + - Record number to update. + - Required for C(state:absent). + required: false + type: str + lookup_field: + description: + - Changes the field that C(number) uses to find records. + required: false + default: number + type: str + attachment: + description: + - Attach a file to the record. + required: false + type: str + display_value: + description: + - sysparm_display_value + type: bool + required: false + default: false + exclude_reference_link: + description: + - sysparm_exclude_reference_link + type: bool + required: false + default: false + suppress_pagination_header: + description: + - sysparm_suppress_pagination_header + type: bool + required: false + default: false +requirements: + - python pysnow (pysnow) +author: + - Tim Rightnour (@garbled1) +extends_documentation_fragment: +- servicenow.servicenow.service_now.documentation + +''' + +EXAMPLES = r''' +- name: Grab a user record + servicenow.servicenow.snow_record: + username: ansible_test + password: my_password + instance: dev99999 + state: present + number: 62826bf03710200044e0bfc8bcbe5df1 + table: sys_user + lookup_field: sys_id + +- name: Grab a user record using OAuth + servicenow.servicenow.snow_record: + username: ansible_test + password: my_password + client_id: "1234567890abcdef1234567890abcdef" + client_secret: "Password1!" + instance: dev99999 + state: present + number: 62826bf03710200044e0bfc8bcbe5df1 + table: sys_user + lookup_field: sys_id + +- name: Create an incident + servicenow.servicenow.snow_record: + username: ansible_test + password: my_password + instance: dev99999 + state: present + data: + short_description: "This is a test incident opened by Ansible" + severity: 3 + priority: 2 + register: new_incident + +- name: Create an incident using host instead of instance + servicenow.servicenow.snow_record: + username: ansible_test + password: my_password + host: dev99999.mycustom.domain.com + state: present + data: + short_description: "This is a test incident opened by Ansible" + priority: 2 + +- name: Delete the record we just made + servicenow.servicenow.snow_record: + username: admin + password: xxxxxxx + instance: dev99999 + state: absent + number: "{{new_incident['record']['number']}}" + +- name: Delete a non-existant record + servicenow.servicenow.snow_record: + username: ansible_test + password: my_password + instance: dev99999 + state: absent + number: 9872354 + failed_when: false + +- name: Update an incident + servicenow.servicenow.snow_record: + username: ansible_test + password: my_password + instance: dev99999 + state: present + number: INC0000055 + data: + work_notes : "Been working all day on this thing." + +- name: Attach a file to an incident + servicenow.servicenow.snow_record: + username: ansible_test + password: my_password + instance: dev99999 + state: present + number: INC0000055 + attachment: README.md + tags: attach +''' + +RETURN = r''' +record: + description: Record data from Service Now + type: dict + returned: when supported +attached_file: + description: Details of the file that was attached via C(attachment) + type: dict + returned: when supported +''' + +import os + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils._text import to_bytes, to_native +from ansible_collections.servicenow.servicenow.plugins.module_utils.service_now import ServiceNowClient + +try: + # This is being handled by ServiceNowClient + import pysnow +except ImportError: + pass + + +def run_module(): + # define the available arguments/parameters that a user can pass to + # the module + module_args = ServiceNowClient.snow_argument_spec() + module_args.update( + table=dict(type='str', required=False, default='incident'), + state=dict(choices=['present', 'absent'], + type='str', required=True), + number=dict(default=None, required=False, type='str'), + data=dict(default=None, required=False, type='dict'), + lookup_field=dict(default='number', required=False, type='str'), + attachment=dict(default=None, required=False, type='str'), + display_value=dict(default=False, type='bool', required=False), + exclude_reference_link=dict(default=False, type='bool', required=False), + suppress_pagination_header=dict(default=False, type='bool', required=False) + ) + module_required_together = [ + ['client_id', 'client_secret'] + ] + module_required_if = [ + ['state', 'absent', ['number']], + ] + + module_mutually_exclusive = [ + ['host', 'instance'], + ] + + module_required_one_of = [ + ['host', 'instance'], + ] + + module = AnsibleModule( + argument_spec=module_args, + supports_check_mode=True, + required_together=module_required_together, + required_if=module_required_if, + required_one_of=module_required_one_of, + mutually_exclusive=module_mutually_exclusive, + ) + + # Connect to ServiceNow + service_now_client = ServiceNowClient(module) + service_now_client.login() + conn = service_now_client.conn + + params = module.params + instance = params['instance'] + host = params['host'] + table = params['table'] + state = params['state'] + number = params['number'] + data = params['data'] + lookup_field = params['lookup_field'] + display_value = params['display_value'] + exclude_reference_link = params['exclude_reference_link'] + suppress_pagination_header = params['suppress_pagination_header'] + + result = dict( + changed=False, + instance=instance, + host=host, + table=table, + number=number, + lookup_field=lookup_field, + display_value=display_value, + exclude_reference_link=exclude_reference_link, + suppress_pagination_header=suppress_pagination_header + ) + + # check for attachments + if params['attachment'] is not None: + attach = params['attachment'] + b_attach = to_bytes(attach, errors='surrogate_or_strict') + if not os.path.exists(b_attach): + module.fail_json(msg="Attachment {0} not found".format(attach)) + result['attachment'] = attach + else: + attach = None + + conn.parameters.display_value = display_value + conn.parameters.exclude_reference_link = exclude_reference_link + conn.parameters.suppress_pagination_header = suppress_pagination_header + + # Deal with check mode + if module.check_mode: + + # if we are in check mode and have no number, we would have created + # a record. We can only partially simulate this + if number is None: + result['record'] = dict(data) + result['changed'] = True + + # do we want to check if the record is non-existent? + elif state == 'absent': + try: + resource = conn.resource(api_path='/table/' + table) + response = resource.get(query={lookup_field: number}) + res = response.one() + result['record'] = dict(Success=True) + result['changed'] = True + except pysnow.exceptions.NoResults: + result['record'] = None + except Exception as detail: + module.fail_json(msg="Unknown failure in query record: {0}".format(to_native(detail)), **result) + + # Let's simulate modification + else: + try: + resource = conn.resource(api_path='/table/' + table) + response = resource.get(query={lookup_field: number}) + res = response.one() + for key, value in data.items(): + res[key] = value + result['changed'] = True + result['record'] = res + except pysnow.exceptions.NoResults: + snow_error = "Record does not exist" + module.fail_json(msg=snow_error, **result) + except Exception as detail: + module.fail_json(msg="Unknown failure in query record: {0}".format(to_native(detail)), **result) + module.exit_json(**result) + + # now for the real thing: (non-check mode) + + # are we creating a new record? + if state == 'present' and number is None: + try: + resource = conn.resource(api_path='/table/' + table) + response = resource.create(payload=dict(data)) + record = response.one() + except pysnow.exceptions.UnexpectedResponseFormat as e: + snow_error = "Failed to create record: {0}, details: {1}".format(e.error_summary, e.error_details) + module.fail_json(msg=snow_error, **result) + except pysnow.legacy_exceptions.UnexpectedResponse as e: + module.fail_json(msg="Failed to create record due to %s" % to_native(e), **result) + result['record'] = record + result['changed'] = True + + # we are deleting a record + elif state == 'absent': + try: + resource = conn.resource(api_path='/table/' + table) + res = resource.delete(query={lookup_field: number}) + except pysnow.exceptions.NoResults: + res = dict(Success=True) + except pysnow.exceptions.MultipleResults: + snow_error = "Multiple record match" + module.fail_json(msg=snow_error, **result) + except pysnow.exceptions.UnexpectedResponseFormat as e: + snow_error = "Failed to delete record: {0}, details: {1}".format(e.error_summary, e.error_details) + module.fail_json(msg=snow_error, **result) + except pysnow.legacy_exceptions.UnexpectedResponse as e: + module.fail_json(msg="Failed to delete record due to %s" % to_native(e), **result) + except Exception as detail: + snow_error = "Failed to delete record: {0}".format(to_native(detail)) + module.fail_json(msg=snow_error, **result) + result['record'] = res + result['changed'] = True + + # We want to update a record + else: + try: + resource = conn.resource(api_path='/table/' + table) + response = resource.get(query={lookup_field: number}) + record = response.one() + if data is not None: + res = response.update(data) + result['record'] = record + result['changed'] = True + else: + result['record'] = record + if attach is not None: + res = record.attach(b_attach) + result['changed'] = True + result['attached_file'] = res + + except pysnow.exceptions.MultipleResults: + snow_error = "Multiple record match" + module.fail_json(msg=snow_error, **result) + except pysnow.exceptions.NoResults: + snow_error = "Record does not exist" + module.fail_json(msg=snow_error, **result) + except pysnow.exceptions.UnexpectedResponseFormat as e: + snow_error = "Failed to update record: {0}, details: {1}".format(e.error_summary, e.error_details) + module.fail_json(msg=snow_error, **result) + except pysnow.legacy_exceptions.UnexpectedResponse as e: + module.fail_json(msg="Failed to update record due to %s" % to_native(e), **result) + except Exception as detail: + snow_error = "Failed to update record: {0}".format(to_native(detail)) + module.fail_json(msg=snow_error, **result) + + module.exit_json(**result) + + +def main(): + run_module() + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/servicenow/servicenow/plugins/modules/snow_record_find.py b/collections-debian-merged/ansible_collections/servicenow/servicenow/plugins/modules/snow_record_find.py new file mode 100644 index 00000000..b6e79b65 --- /dev/null +++ b/collections-debian-merged/ansible_collections/servicenow/servicenow/plugins/modules/snow_record_find.py @@ -0,0 +1,318 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2017, Tim Rightnour <thegarbledone@gmail.com> +# 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 + +DOCUMENTATION = r''' +--- +module: snow_record_find +short_description: Search for multiple records from ServiceNow +description: + - Gets multiple records from a specified table from ServiceNow based on a query dictionary. +options: + table: + description: + - Table to query for records. + type: str + required: false + default: incident + query: + description: + - Dict to query for records. + type: dict + required: true + max_records: + description: + - Maximum number of records to return. + type: int + required: false + default: 20 + display_value: + description: + - sysparm_display_value + type: bool + required: false + default: false + exclude_reference_link: + description: + - sysparm_exclude_reference_link + type: bool + required: false + default: false + suppress_pagination_header: + description: + - sysparm_suppress_pagination_header + type: bool + required: false + default: false + order_by: + description: + - Field to sort the results on. + - Can prefix with "-" or "+" to change descending or ascending sort order. + type: str + default: "-created_on" + required: false + return_fields: + description: + - Fields of the record to return in the json. + - By default, all fields will be returned. + type: list + required: false + elements: str +requirements: + - python pysnow (pysnow) +author: + - Tim Rightnour (@garbled1) +extends_documentation_fragment: +- servicenow.servicenow.service_now.documentation + +''' + +EXAMPLES = r''' +- name: Search for incident assigned to group, return specific fields + servicenow.servicenow.snow_record_find: + username: ansible_test + password: my_password + instance: dev99999 + table: incident + query: + assignment_group: d625dccec0a8016700a222a0f7900d06 + return_fields: + - number + - opened_at + +- name: Search for incident using host instead of instance + servicenow.servicenow.snow_record_find: + username: ansible_test + password: my_password + host: dev99999.mycustom.domain.com + table: incident + query: + assignment_group: d625dccec0a8016700a222a0f7900d06 + return_fields: + - number + - opened_at + +- name: Using OAuth, search for incident assigned to group, return specific fields + servicenow.servicenow.snow_record_find: + username: ansible_test + password: my_password + client_id: "1234567890abcdef1234567890abcdef" + client_secret: "Password1!" + instance: dev99999 + table: incident + query: + assignment_group: d625dccec0a8016700a222a0f7900d06 + return_fields: + - number + - opened_at + +- name: Find open standard changes with my template + servicenow.servicenow.snow_record_find: + username: ansible_test + password: my_password + instance: dev99999 + table: change_request + query: + AND: + equals: + active: "True" + type: "standard" + u_change_stage: "80" + contains: + u_template: "MY-Template" + return_fields: + - sys_id + - number + - sys_created_on + - sys_updated_on + - u_template + - active + - type + - u_change_stage + - sys_created_by + - description + - short_description +''' + +RETURN = r''' +record: + description: The full contents of the matching ServiceNow records as a list of records. + type: dict + returned: always +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.servicenow.servicenow.plugins.module_utils.service_now import ServiceNowClient +from ansible.module_utils._text import to_native + +try: + # This is being managed by ServiceNowClient + import pysnow +except ImportError: + pass + + +class BuildQuery(object): + ''' + This is a BuildQuery manipulation class that constructs + a pysnow.QueryBuilder object based on data input. + ''' + + def __init__(self, module): + self.module = module + self.logic_operators = ["AND", "OR", "NQ"] + self.condition_operator = { + 'equals': self._condition_closure, + 'not_equals': self._condition_closure, + 'contains': self._condition_closure, + 'not_contains': self._condition_closure, + 'starts_with': self._condition_closure, + 'ends_with': self._condition_closure, + 'greater_than': self._condition_closure, + 'less_than': self._condition_closure, + } + self.accepted_cond_ops = self.condition_operator.keys() + self.append_operator = False + self.simple_query = True + self.data = module.params['query'] + + def _condition_closure(self, cond, query_field, query_value): + self.qb.field(query_field) + getattr(self.qb, cond)(query_value) + + def _iterate_fields(self, data, logic_op, cond_op): + if isinstance(data, dict): + for query_field, query_value in data.items(): + if self.append_operator: + getattr(self.qb, logic_op)() + self.condition_operator[cond_op](cond_op, query_field, query_value) + self.append_operator = True + else: + self.module.fail_json(msg='Query is not in a supported format') + + def _iterate_conditions(self, data, logic_op): + if isinstance(data, dict): + for cond_op, fields in data.items(): + if (cond_op in self.accepted_cond_ops): + self._iterate_fields(fields, logic_op, cond_op) + else: + self.module.fail_json(msg='Supported conditions: {0}'.format(str(self.condition_operator.keys()))) + else: + self.module.fail_json(msg='Supported conditions: {0}'.format(str(self.condition_operator.keys()))) + + def _iterate_operators(self, data): + if isinstance(data, dict): + for logic_op, cond_op in data.items(): + if (logic_op in self.logic_operators): + self.simple_query = False + self._iterate_conditions(cond_op, logic_op) + elif self.simple_query: + self.condition_operator['equals']('equals', logic_op, cond_op) + break + else: + self.module.fail_json(msg='Query is not in a supported format') + else: + self.module.fail_json(msg='Supported operators: {0}'.format(str(self.logic_operators))) + + def build_query(self): + self.qb = pysnow.QueryBuilder() + self._iterate_operators(self.data) + return (self.qb) + + +def run_module(): + # define the available arguments/parameters that a user can pass to + # the module + module_args = ServiceNowClient.snow_argument_spec() + module_args.update( + table=dict(type='str', required=False, default='incident'), + query=dict(type='dict', required=True), + max_records=dict(default=20, type='int', required=False), + display_value=dict(default=False, type='bool', required=False), + exclude_reference_link=dict(default=False, type='bool', required=False), + suppress_pagination_header=dict(default=False, type='bool', required=False), + order_by=dict(default='-created_on', type='str', required=False), + return_fields=dict(default=[], type='list', required=False, elements='str') + ) + module_required_together = [ + ['client_id', 'client_secret'] + ] + + module_mutually_exclusive = [ + ['host', 'instance'], + ] + + module_required_one_of = [ + ['host', 'instance'], + ] + + module = AnsibleModule( + argument_spec=module_args, + supports_check_mode=True, + required_together=module_required_together, + required_one_of=module_required_one_of, + mutually_exclusive=module_mutually_exclusive, + ) + + # Connect to ServiceNow + service_now_client = ServiceNowClient(module) + service_now_client.login() + conn = service_now_client.conn + + params = module.params + instance = params['instance'] + host = params['host'] + table = params['table'] + query = params['query'] + max_records = params['max_records'] + display_value = params['display_value'] + exclude_reference_link = params['exclude_reference_link'] + suppress_pagination_header = params['suppress_pagination_header'] + return_fields = params['return_fields'] + + result = dict( + changed=False, + instance=instance, + host=host, + table=table, + query=query, + max_records=max_records, + display_value=display_value, + exclude_reference_link=exclude_reference_link, + suppress_pagination_header=suppress_pagination_header, + return_fields=return_fields + ) + + # Do the lookup + try: + bq = BuildQuery(module) + qb = bq.build_query() + table = conn.resource(api_path='/table/' + table) + + table.parameters.display_value = display_value + table.parameters.exclude_reference_link = exclude_reference_link + table.parameters.suppress_pagination_header = suppress_pagination_header + + response = table.get( + query=qb, + limit=max_records, + fields=return_fields) + except Exception as detail: + module.fail_json(msg='Failed to find record: {0}'.format(to_native(detail)), **result) + + result['record'] = response.all() + + module.exit_json(**result) + + +def main(): + run_module() + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/servicenow/servicenow/requirements.txt b/collections-debian-merged/ansible_collections/servicenow/servicenow/requirements.txt new file mode 100644 index 00000000..45188e65 --- /dev/null +++ b/collections-debian-merged/ansible_collections/servicenow/servicenow/requirements.txt @@ -0,0 +1,2 @@ +pysnow +netaddr diff --git a/collections-debian-merged/ansible_collections/servicenow/servicenow/tests/enhanced.now.yml b/collections-debian-merged/ansible_collections/servicenow/servicenow/tests/enhanced.now.yml new file mode 100644 index 00000000..bc0f1787 --- /dev/null +++ b/collections-debian-merged/ansible_collections/servicenow/servicenow/tests/enhanced.now.yml @@ -0,0 +1,10 @@ +--- +plugin: servicenow.servicenow.now +instance: dev93775.service-now.com +username: admin +password: knTVFcRlD6d9 +selection_order: name +enhanced: True +#keyed_groups: +# - key: sn_sys_class_name +# prefix: sn diff --git a/collections-debian-merged/ansible_collections/servicenow/servicenow/tests/module_test.yml b/collections-debian-merged/ansible_collections/servicenow/servicenow/tests/module_test.yml new file mode 100644 index 00000000..8a8b85b7 --- /dev/null +++ b/collections-debian-merged/ansible_collections/servicenow/servicenow/tests/module_test.yml @@ -0,0 +1,36 @@ +--- +- hosts: localhost + gather_facts: no + vars: + sn_instance: dev89007 + login: &login + username: admin + password: ha53wiaYCKDX + + tasks: + - name: test with instance + servicenow.servicenow.snow_record: + state: present + table: change_request + instance: "{{ sn_instance }}" + data: + short_description: "Test 1 from Ansible Collection" + <<: *login + + - name: test with instance + servicenow.servicenow.snow_record: + state: present + table: change_request + host: "{{ sn_instance }}.service-now.com" + data: + short_description: "Test 2 from Ansible Collection" + <<: *login + + - name: find test records + servicenow.servicenow.snow_record_find: + table: change_request + instance: "{{ sn_instance }}" + query: + starts_with: + - short_description: "Test" + <<: *login
\ No newline at end of file diff --git a/collections-debian-merged/ansible_collections/servicenow/servicenow/tests/module_test_cmdb_ci_server.yml b/collections-debian-merged/ansible_collections/servicenow/servicenow/tests/module_test_cmdb_ci_server.yml new file mode 100644 index 00000000..fbe3a1bd --- /dev/null +++ b/collections-debian-merged/ansible_collections/servicenow/servicenow/tests/module_test_cmdb_ci_server.yml @@ -0,0 +1,220 @@ +--- +- hosts: localhost + gather_facts: no + vars: + sn_instance: dev89007 + login: &login + username: admin + password: ha53wiaYCKDX + + tasks: + - set_fact: + name_prefix: "{{ lookup('password', '/dev/null chars=ascii_lowercase,digits length=8') }}" + + # create + - name: test create record + servicenow.servicenow.snow_record: + state: present + table: cmdb_ci_server + instance: "{{ sn_instance }}" + display_value: True + data: + name: test-{{ name_prefix }}-00{{ item }} + <<: *login + register: result + loop: [11, 12, 21, 22] + + - assert: + that: + - result.results is defined + - result.results|length == 4 + - result.results[0].record is defined + - result.results[0].record.name is defined + - result.results[0].record.name == "test-{{ name_prefix }}-0011" + - result.results[0].record.sys_domain is defined + - result.results[0].record.sys_domain.display_value is defined + - result.results[0].record.sys_domain.display_value == "global" + + # update + - name: test update one record + servicenow.servicenow.snow_record: + host: "{{ sn_instance }}.service-now.com" + table: cmdb_ci_server + lookup_field: name + number: "test-{{ name_prefix }}-0022" + data: + short_description: comment1 + state: present + <<: *login + register: result + + - assert: + that: + - result.changed + + - name: test update, find updated record + servicenow.servicenow.snow_record_find: + host: "{{ sn_instance }}.service-now.com" + table: cmdb_ci_server + query: + name: "test-{{ name_prefix }}-0022" + <<: *login + register: result + + - assert: + that: + - result.record is defined + - result.record|length == 1 + - result.record[0].name is defined + - result.record[0].name == "test-{{ name_prefix }}-0022" + - result.record[0].short_description is defined + - result.record[0].short_description == "comment1" + + # search + - name: test find one record + servicenow.servicenow.snow_record_find: + host: "{{ sn_instance }}.service-now.com" + table: cmdb_ci_server + query: + name: test-{{ name_prefix }}-0022 + <<: *login + register: result + + - assert: + that: + - result.record|length == 1 + - result.record[0].name is defined + - result.record[0].name == "test-{{ name_prefix }}-0022" + + - name: test find one record, return_fields + servicenow.servicenow.snow_record_find: + host: "{{ sn_instance }}.service-now.com" + table: cmdb_ci_server + return_fields: + - name + - short_description + query: + name: test-{{ name_prefix }}-0011 + <<: *login + register: result + + - assert: + that: + - result.record|length == 1 + - result.record[0]|length == 2 + - result.record[0].name is defined + - result.record[0].short_description is defined + + - name: test find one out of many record + servicenow.servicenow.snow_record_find: + host: "{{ sn_instance }}.service-now.com" + table: cmdb_ci_server + query: + name: test-{{ name_prefix }}-0011 + <<: *login + register: result + + - assert: + that: + - result.record|length == 1 + - result.record[0].name == "test-{{ name_prefix }}-0011" + - result.record[0].model_id is defined + - result.record[0].model_id.link is defined + + - name: test find one out of many record with display_value=True + servicenow.servicenow.snow_record_find: + host: "{{ sn_instance }}.service-now.com" + table: cmdb_ci_server + display_value: True + query: + name: test-{{ name_prefix }}-0011 + <<: *login + register: result + + - assert: + that: + - result.record|length == 1 + - result.display_value + - not result.exclude_reference_link + - result.record[0].name == "test-{{ name_prefix }}-0011" + - result.record[0].sys_domain is defined + - result.record[0].sys_domain.display_value is defined + - result.record[0].sys_domain.display_value == "global" + + - name: test find one out of many record with display_value=True exclude_reference_link=True + servicenow.servicenow.snow_record_find: + host: "{{ sn_instance }}.service-now.com" + table: cmdb_ci_server + display_value: True + exclude_reference_link: True + query: + name: test-{{ name_prefix }}-0011 + <<: *login + register: result + + - assert: + that: + - result.display_value + - result.exclude_reference_link + - result.record|length == 1 + - result.record[0].name == "test-{{ name_prefix }}-0011" + - result.record[0].model_id is defined + - result.record[0].model_id == "Unknown" + + - name: test find only 2 records out of many + servicenow.servicenow.snow_record_find: + host: "{{ sn_instance }}.service-now.com" + table: cmdb_ci_server + query: + AND: + contains: + name: "test-{{ name_prefix }}-001" + <<: *login + register: result + + - assert: + that: + - result.record|length == 2 + + - name: test find many, want only 3 + servicenow.servicenow.snow_record_find: + host: "{{ sn_instance }}.service-now.com" + table: cmdb_ci_server + max_records: 3 + query: + AND: + contains: + name: "test-{{ name_prefix }}" + <<: *login + register: result + + - assert: + that: + - result.record|length == 3 + + # remove + - name: remove record + servicenow.servicenow.snow_record: + state: absent + table: cmdb_ci_server + instance: "{{ sn_instance }}" + number: "test-{{ name_prefix }}-00{{ item }}" + lookup_field: name + <<: *login + loop: [11, 12, 21, 22] + + # search result is empty + - name: test find no record + servicenow.servicenow.snow_record_find: + host: "{{ sn_instance }}.service-now.com" + table: cmdb_ci_server + query: + AND: + contains: + name: "test-{{ name_prefix }}" + <<: *login + register: result + + - assert: + that: + - result.record|length == 0 diff --git a/collections-debian-merged/ansible_collections/servicenow/servicenow/tests/network.enhanced.now.yml b/collections-debian-merged/ansible_collections/servicenow/servicenow/tests/network.enhanced.now.yml new file mode 100644 index 00000000..ebe1d395 --- /dev/null +++ b/collections-debian-merged/ansible_collections/servicenow/servicenow/tests/network.enhanced.now.yml @@ -0,0 +1,8 @@ +--- +plugin: servicenow.servicenow.now +instance: dev93775.service-now.com +username: admin +password: le4MnTLd3bCK +table: cmdb_ci_netgear +selection_order: name +enhanced: True diff --git a/collections-debian-merged/ansible_collections/servicenow/servicenow/tests/now.yml b/collections-debian-merged/ansible_collections/servicenow/servicenow/tests/now.yml new file mode 100644 index 00000000..449c58f0 --- /dev/null +++ b/collections-debian-merged/ansible_collections/servicenow/servicenow/tests/now.yml @@ -0,0 +1,26 @@ +--- +plugin: servicenow.servicenow.now +host: dev95176.service-now.com +username: admin +password: P0aX7VAtnyXm +selection_order: name +fields: + - os + - ip_address + - fqdn + - host_name + - sys_class_name + - name + - disk_space + - cpu_count +groups: + large: (sn_disk_space | int) > 100 + SAP: inventory_hostname.startswith('SAP') +keyed_groups: + - key: sn_sys_class_name + prefix: sn + - key: os_class + prefix: '' + separator: '' +compose: + os_class: sn_os.split(' ')[0]
\ No newline at end of file diff --git a/collections-debian-merged/ansible_collections/servicenow/servicenow/update_sets/README.md b/collections-debian-merged/ansible_collections/servicenow/servicenow/update_sets/README.md new file mode 100644 index 00000000..d3990837 --- /dev/null +++ b/collections-debian-merged/ansible_collections/servicenow/servicenow/update_sets/README.md @@ -0,0 +1,5 @@ +# Update Sets for Ansible Integration +This directory provides update sets that may be required to unlock functionality in ServiceNow. + +## ansible_enhanced_inventory +This update set installs a scripted REST API into your ServiceNow instance. This is required for the `enhanced` parameter in the `now` inventory plugin to function. "enhanced" provides CI relationship data to the plugin so that it can build additional groups in your inventory.
\ No newline at end of file diff --git a/collections-debian-merged/ansible_collections/servicenow/servicenow/update_sets/ansible_enhanced_inventory.xml b/collections-debian-merged/ansible_collections/servicenow/servicenow/update_sets/ansible_enhanced_inventory.xml new file mode 100644 index 00000000..ddcf7976 --- /dev/null +++ b/collections-debian-merged/ansible_collections/servicenow/servicenow/update_sets/ansible_enhanced_inventory.xml @@ -0,0 +1,219 @@ +<?xml version="1.0" encoding="UTF-8"?><unload unload_date="2020-01-30 23:28:32"> +<sys_remote_update_set action="INSERT_OR_UPDATE"> +<application display_value="Global">global</application> +<application_name>Global</application_name> +<application_scope>global</application_scope> +<application_version/> +<collisions/> +<commit_date/> +<deleted/> +<description/> +<inserted/> +<name>Ansible_Inventory</name> +<origin_sys_id/> +<parent display_value=""/> +<release_date/> +<remote_base_update_set display_value=""/> +<remote_parent_id/> +<remote_sys_id>d9552962db66481085449eb5db961931</remote_sys_id> +<state>loaded</state> +<summary/> +<sys_class_name>sys_remote_update_set</sys_class_name> +<sys_created_by>admin</sys_created_by> +<sys_created_on>2020-01-30 23:28:31</sys_created_on> +<sys_id>674a39afdb220010081a3ec8f496197d</sys_id> +<sys_mod_count>0</sys_mod_count> +<sys_updated_by>admin</sys_updated_by> +<sys_updated_on>2020-01-30 23:28:31</sys_updated_on> +<update_set display_value=""/> +<update_source display_value=""/> +<updated/> +</sys_remote_update_set> +<sys_update_xml action="INSERT_OR_UPDATE"> +<action>INSERT_OR_UPDATE</action> +<application display_value="Global">global</application> +<category>customer</category> +<comments/> +<name>sys_ws_query_parameter_map_9e0a692adb66481085449eb5db961931</name> +<payload><![CDATA[<?xml version="1.0" encoding="UTF-8"?><record_update table="sys_ws_query_parameter_map"><sys_ws_query_parameter_map action="INSERT_OR_UPDATE"><sys_class_name>sys_ws_query_parameter_map</sys_class_name><sys_created_by>admin</sys_created_by><sys_created_on>2020-01-27 19:44:45</sys_created_on><sys_customer_update>false</sys_customer_update><sys_id>9e0a692adb66481085449eb5db961931</sys_id><sys_mod_count>0</sys_mod_count><sys_name>3f2a692adb66481085449eb5db9619e2</sys_name><sys_package display_value="Global" source="global">global</sys_package><sys_policy/><sys_replace_on_upgrade>false</sys_replace_on_upgrade><sys_scope display_value="Global">global</sys_scope><sys_update_name>sys_ws_query_parameter_map_9e0a692adb66481085449eb5db961931</sys_update_name><sys_updated_by>admin</sys_updated_by><sys_updated_on>2020-01-27 19:44:45</sys_updated_on><web_service_operation display_value="Ansible Inventory">20b521a2db66481085449eb5db96190f</web_service_operation><web_service_query_parameter display_value="sysparm_fields">3f2a692adb66481085449eb5db9619e2</web_service_query_parameter></sys_ws_query_parameter_map></record_update>]]></payload> +<payload_hash>1820109461</payload_hash> +<remote_update_set display_value="Ansible_Inventory">674a39afdb220010081a3ec8f496197d</remote_update_set> +<replace_on_upgrade>false</replace_on_upgrade> +<sys_created_by>admin</sys_created_by> +<sys_created_on>2020-01-30 23:28:31</sys_created_on> +<sys_id>2b4a39afdb220010081a3ec8f496197e</sys_id> +<sys_mod_count>0</sys_mod_count> +<sys_recorded_at>16fe888ecab0000001</sys_recorded_at> +<sys_updated_by>admin</sys_updated_by> +<sys_updated_on>2020-01-30 23:28:31</sys_updated_on> +<table/> +<target_name>3f2a692adb66481085449eb5db9619e2</target_name> +<type>Scripted REST Query Parameter Associatio</type> +<update_domain>global</update_domain> +<update_guid>645a2d2a0d6648100f79ab3c3f9ebb43</update_guid> +<update_guid_history>645a2d2a0d6648100f79ab3c3f9ebb43:1820109461</update_guid_history> +<update_set display_value=""/> +<view/> +</sys_update_xml> +<sys_update_xml action="INSERT_OR_UPDATE"> +<action>INSERT_OR_UPDATE</action> +<application display_value="Global">global</application> +<category>customer</category> +<comments/> +<name>sys_ws_query_parameter_3f2a692adb66481085449eb5db9619e2</name> +<payload><![CDATA[<?xml version="1.0" encoding="UTF-8"?><record_update table="sys_ws_query_parameter"><sys_ws_query_parameter action="INSERT_OR_UPDATE"><example_value>fqdn,host_name,ip_address,name,sys_class_name</example_value><name>sysparm_fields</name><required>true</required><short_description>field paramters for searching cmdb_ci_server</short_description><sys_class_name>sys_ws_query_parameter</sys_class_name><sys_created_by>admin</sys_created_by><sys_created_on>2020-01-27 19:44:42</sys_created_on><sys_customer_update>false</sys_customer_update><sys_id>3f2a692adb66481085449eb5db9619e2</sys_id><sys_mod_count>1</sys_mod_count><sys_name>sysparm_fields</sys_name><sys_package display_value="Global" source="global">global</sys_package><sys_policy/><sys_replace_on_upgrade>false</sys_replace_on_upgrade><sys_scope display_value="Global">global</sys_scope><sys_update_name>sys_ws_query_parameter_3f2a692adb66481085449eb5db9619e2</sys_update_name><sys_updated_by>admin</sys_updated_by><sys_updated_on>2020-01-27 19:44:54</sys_updated_on><web_service_definition display_value="Ansible Inventory">8e95e962db66481085449eb5db961952</web_service_definition></sys_ws_query_parameter></record_update>]]></payload> +<payload_hash>735828070</payload_hash> +<remote_update_set display_value="Ansible_Inventory">674a39afdb220010081a3ec8f496197d</remote_update_set> +<replace_on_upgrade>false</replace_on_upgrade> +<sys_created_by>admin</sys_created_by> +<sys_created_on>2020-01-30 23:28:31</sys_created_on> +<sys_id>674a39afdb220010081a3ec8f496197e</sys_id> +<sys_mod_count>0</sys_mod_count> +<sys_recorded_at>16fe8890fae0000001</sys_recorded_at> +<sys_updated_by>admin</sys_updated_by> +<sys_updated_on>2020-01-30 23:28:31</sys_updated_on> +<table/> +<target_name>sysparm_fields</target_name> +<type>Scripted REST Query Parameter</type> +<update_domain>global</update_domain> +<update_guid>625aed2ab966481080dc3bfae30dadbd</update_guid> +<update_guid_history>625aed2ab966481080dc3bfae30dadbd:735828070,7f4ae92a586648109b769b2578bf6652:-407882821</update_guid_history> +<update_set display_value=""/> +<view/> +</sys_update_xml> +<sys_update_xml action="INSERT_OR_UPDATE"> +<action>INSERT_OR_UPDATE</action> +<application display_value="Global">global</application> +<category>customer</category> +<comments/> +<name>sys_ws_operation_20b521a2db66481085449eb5db96190f</name> +<payload><?xml version="1.0" encoding="UTF-8"?><record_update table="sys_ws_operation"><sys_ws_operation action="INSERT_OR_UPDATE"><active>true</active><consumes>application/json,application/xml,text/xml</consumes><consumes_customized>false</consumes_customized><default_operation_uri/><enforce_acl>cf9d01d3e73003009d6247e603f6a990</enforce_acl><http_method>GET</http_method><name>Ansible Inventory</name><operation_script><![CDATA[(function process( /*RESTAPIRequest*/ request, /*RESTAPIResponse*/ response) { + + function getRelatedSubCI(sys_id, target) { + + var gp = []; + var a = sys_id; //current.cmdb_ci; + + //cmdb_rel_ci has the relationship to child CIs + var grp = new GlideRecord('cmdb_rel_ci'); + grp.addQuery(target, a); + grp.query(); + + var x = 0; + while (grp.next()) { + gp[x] = {}; + target == 'parent' ? gp[x].ci_type = grp.child.sys_class_name.getDisplayValue() : gp[x].ci_type = grp.parent.sys_class_name.getDisplayValue(); + gp[x].ci_rel_type = grp.type.getDisplayValue().replace(/\s|:/g, "_"); + target == 'parent' ? gp[x].ci = grp.child.name : gp[x].ci = grp.parent.name; + x++; + } + + return gp; + } + + if (!request.queryParams.sysparm_fields) { + response.setStatus(400); + response.setContentType('application/json'); + response.setError(new sn_ws_err.BadRequestError("no sysparm_fields query param")); + } else if (!request.queryParams.table) { + response.setStatus(400); + response.setContentType('application/json'); + response.setError(new sn_ws_err.BadRequestError("no table specified")); + } else { + + var queryString = "sysparm_exclude_reference_link=false&sysparm_display_value=true&sysparm_fields=" + request.queryParams.sysparm_fields + "&sysparm_query"; + + var table = request.queryParams.table; + + if (!/^cmdb_ci_/.test(table)) { + response.setStatus(400); + response.setContentType('application/json'); + response.setError(new sn_ws_err.BadRequestError("table must be a child of cmdb_ci")); + } else if (!gs.tableExists(table)) { + response.setStatus(400); + response.setContentType('application/json'); + response.setError(new sn_ws_err.BadRequestError("specified table "+table+" does not exist")); + } else { + + var regexp = /^.+sysparm_fields\=(.*)\&\w*/; + var fields = (queryString.match(regexp))[1].split(','); + + var gr = new GlideRecord(table); + gr.addEncodedQuery(queryString); + gr.query(); + + var results = { + 'result': [] + }; + var i = 0; + var parent = {}; + var child = {}; + + while (gr.next()) { + + parent = getRelatedSubCI(gr.sys_id, 'parent'); + child = getRelatedSubCI(gr.sys_id, 'child'); + results['result'][i] = { + //'parent': parent.ci, + 'parent_relationships': parent, + //'child': child.ci, + 'child_relationships': child + }; + for (y in fields) { + results['result'][i][fields[y]] = gr.getDisplayValue(fields[y]); + } + i++; + } + response.setContentType('application/json'); + response.setStatus(200); + response.setBody(results.result); + } + } + +})(request, response);]]></operation_script><operation_uri>/api/snc/ansible_inventory</operation_uri><produces>application/json,application/xml,text/xml</produces><produces_customized>false</produces_customized><relative_path>/</relative_path><request_example/><requires_acl_authorization>true</requires_acl_authorization><requires_authentication>true</requires_authentication><requires_snc_internal_role>false</requires_snc_internal_role><short_description/><sys_class_name>sys_ws_operation</sys_class_name><sys_created_by>admin</sys_created_by><sys_created_on>2020-01-27 19:24:55</sys_created_on><sys_customer_update>false</sys_customer_update><sys_id>20b521a2db66481085449eb5db96190f</sys_id><sys_mod_count>50</sys_mod_count><sys_name>Ansible Inventory</sys_name><sys_package display_value="Global" source="global">global</sys_package><sys_policy/><sys_replace_on_upgrade>false</sys_replace_on_upgrade><sys_scope display_value="Global">global</sys_scope><sys_update_name>sys_ws_operation_20b521a2db66481085449eb5db96190f</sys_update_name><sys_updated_by>admin</sys_updated_by><sys_updated_on>2020-01-27 21:15:10</sys_updated_on><web_service_definition display_value="Ansible Inventory">8e95e962db66481085449eb5db961952</web_service_definition><web_service_version/></sys_ws_operation></record_update></payload> +<payload_hash>1074422118</payload_hash> +<remote_update_set display_value="Ansible_Inventory">674a39afdb220010081a3ec8f496197d</remote_update_set> +<replace_on_upgrade>false</replace_on_upgrade> +<sys_created_by>admin</sys_created_by> +<sys_created_on>2020-01-30 23:28:31</sys_created_on> +<sys_id>a34a39afdb220010081a3ec8f496197e</sys_id> +<sys_mod_count>0</sys_mod_count> +<sys_recorded_at>16fe8dbb49b0000001</sys_recorded_at> +<sys_updated_by>admin</sys_updated_by> +<sys_updated_on>2020-01-30 23:28:31</sys_updated_on> +<table/> +<target_name>Ansible Inventory</target_name> +<type>Scripted REST Resource</type> +<update_domain>global</update_domain> +<update_guid>0d0f3d669ae648105dfd0d683c641e24</update_guid> +<update_guid_history>0d0f3d669ae648105dfd0d683c641e24:1074422118,856e3d66dae64810343768747a3e321f:1730035206,2e0d7da23fe64810af6f7cfc7e18ad32:-1757677024,664cb5a2dae648105756166f01c41b01:-725853184,4cfbbd6236e648102bad37a1a8234fc1:-208273856,3f6b75ee3fa64810dd4596b8a05625c5:1376315424,955a75ee01a648103b53906e8d3dce6d:430933392,4ef975eee6a648106c3381093f8f6068:1312994583,6fa979aebea6481056a80d7f5a93c575:1636415031,9b7935ae99a6481014c1a8db5451bf1e:914602057,6149f1ae05a64810f588ce90d381f8c4:861040761,47c8b16ecaa64810937cf992b8c7dbef:1332608858,45a8392ec7a64810a79053c31d076568:-1494029102,dd78392e7ca64810ec844c995635c762:542268540,c248392e63a64810ac8ac28574078c38:1768105004,fcd7b92ab3a64810ac2f06ca7ed15758:-528303117,7cb6352a46a648107e490d8685595ae8:75471988,da75752a62a64810a34bc5a8b4651c54:-463417776,3745f9e2f7a648100ae5536a30222939:42335310,30d4f9e61fa6481014d6462867a6942c:-722896322,d3c1f9e222a6481086744cb783d9222f:-1652078180,d46179a2b4a64810396ce345c7af2ac2:-1206689548,0401fd62fda64810160cf8660d193849:-1445231948,d36071ee8866481015a991c63d34c1a6:1000577296,1f6ea56e8f6648102d6d1fcd343ff4e9:-1291387353,1c6d292ee8664810fd96d8dae3cdd0cf:339933249,cd3da12eec664810da6b553cff9071a1:-1931992928,478c69eaff664810c4cbb2f0c55d1efa:-468812462,dd7c69eafd66481043397b64c941abf4:2128744305,7e1ced6a9a664810a8cbdfc72b691bb2:1435735615,3afb6daabf6648103a1b25780cea4656:760621217,918b6daa3f664810efa2299b5daeb851:432563560,11eaed2a066648105911d7a91b242fcf:194023943,42ca216aa7664810be678c16dbedd44a:2132295303,ebf9292a99664810c589e3532d8e8765:-2137588737,02b925e6366648102df9ea72713185cc:-690959945,5839e5a6cc664810967bf75cc69a1215:1463531592,b78825a60366481034c8238c6802af7a:1073365151,526821a6aa664810fc96b9d7f4683c88:-1304589235,fc5861a65a664810a5b30ae1cf7dab34:1045386951,8948ed668f664810b3dbca0553c0e873:746752488,20186966986648107f2f6eb6ca1e1f9b:2119584903,6bd76526dd664810faffa12178ac1b94:1044137095,06a7ad26f86648109a504183943216ba:-1064086520,d28765267d664810cb3c474a040e4ccf:-1800063027,7f472126ac664810a5d32e6fbf80c047:1699569421,60172de27a664810c931e012b3ea1a4b:-856412088,30f62de2a16648107fd0ce8ca70da25f:-1714083000,1ce625a2b1664810fb3910e6405dbd41:311127871,1a2625a20866481066e4e95eebb61146:653669429,0ec525a24666481068bfb434beebdb04:924471465</update_guid_history> +<update_set display_value=""/> +<view/> +</sys_update_xml> +<sys_update_xml action="INSERT_OR_UPDATE"> +<action>INSERT_OR_UPDATE</action> +<application display_value="Global">global</application> +<category>customer</category> +<comments/> +<name>sys_ws_definition_8e95e962db66481085449eb5db961952</name> +<payload><![CDATA[<?xml version="1.0" encoding="UTF-8"?><record_update table="sys_ws_definition"><sys_ws_definition action="INSERT_OR_UPDATE"><active>true</active><base_uri>/api/snc/ansible_inventory</base_uri><consumes>application/json,application/xml,text/xml</consumes><consumes_customized>false</consumes_customized><default_version>No active default version</default_version><doc_link/><enforce_acl>cf9d01d3e73003009d6247e603f6a990</enforce_acl><is_versioned>false</is_versioned><name>Ansible Inventory</name><namespace>snc</namespace><produces>application/json,application/xml,text/xml</produces><produces_customized>false</produces_customized><service_id>ansible_inventory</service_id><short_description/><sys_class_name>sys_ws_definition</sys_class_name><sys_created_by>admin</sys_created_by><sys_created_on>2020-01-27 19:24:14</sys_created_on><sys_customer_update>false</sys_customer_update><sys_id>8e95e962db66481085449eb5db961952</sys_id><sys_mod_count>1</sys_mod_count><sys_name>Ansible Inventory</sys_name><sys_package display_value="Global" source="global">global</sys_package><sys_policy/><sys_replace_on_upgrade>false</sys_replace_on_upgrade><sys_scope display_value="Global">global</sys_scope><sys_update_name>sys_ws_definition_8e95e962db66481085449eb5db961952</sys_update_name><sys_updated_by>admin</sys_updated_by><sys_updated_on>2020-01-27 19:24:29</sys_updated_on></sys_ws_definition></record_update>]]></payload> +<payload_hash>740685616</payload_hash> +<remote_update_set display_value="Ansible_Inventory">674a39afdb220010081a3ec8f496197d</remote_update_set> +<replace_on_upgrade>false</replace_on_upgrade> +<sys_created_by>admin</sys_created_by> +<sys_created_on>2020-01-30 23:28:31</sys_created_on> +<sys_id>eb4a39afdb220010081a3ec8f496197d</sys_id> +<sys_mod_count>0</sys_mod_count> +<sys_recorded_at>16fe8765f720000001</sys_recorded_at> +<sys_updated_by>admin</sys_updated_by> +<sys_updated_on>2020-01-30 23:28:31</sys_updated_on> +<table/> +<target_name>Ansible Inventory</target_name> +<type>Scripted REST API</type> +<update_domain>global</update_domain> +<update_guid>2ba5ad625e664810987a1cee2ddbb698</update_guid> +<update_guid_history>2ba5ad625e664810987a1cee2ddbb698:740685616,08a56d6278664810ea559a69b459e3d0:-1084756942</update_guid_history> +<update_set display_value=""/> +<view/> +</sys_update_xml> +</unload> |