diff options
Diffstat (limited to 'ansible_collections/community/sap')
23 files changed, 221 insertions, 4440 deletions
diff --git a/ansible_collections/community/sap/.github/workflows/ansible-test.yml b/ansible_collections/community/sap/.github/workflows/ansible-test.yml index 1671f6579..c29b8123a 100644 --- a/ansible_collections/community/sap/.github/workflows/ansible-test.yml +++ b/ansible_collections/community/sap/.github/workflows/ansible-test.yml @@ -1,126 +1,126 @@ -name: CI -on: - # Run CI against all pushes (direct commits, also merged PRs), Pull Requests - push: - pull_request: - # Run CI once per day (at 06:00 UTC) - # This ensures that even if there haven't been commits that we are still testing against latest version of ansible-test for each ansible-base version - schedule: - - cron: '0 6 * * *' -env: - NAMESPACE: community - COLLECTION_NAME: sap +# name: CI +# on: +# # Run CI against all pushes (direct commits, also merged PRs), Pull Requests +# push: +# pull_request: +# # Run CI once per day (at 06:00 UTC) +# # This ensures that even if there haven't been commits that we are still testing against latest version of ansible-test for each ansible-base version +# schedule: +# - cron: '0 6 * * *' +# env: +# NAMESPACE: community +# COLLECTION_NAME: sap -jobs: - sanity: - name: Sanity (Ⓐ${{ matrix.ansible }}) - strategy: - matrix: - ansible: - - stable-2.9 - - stable-2.10 - - stable-2.11 - - stable-2.12 - - devel - runs-on: ubuntu-latest - steps: +# jobs: +# sanity: +# name: Sanity (Ⓐ${{ matrix.ansible }}) +# strategy: +# matrix: +# ansible: +# - stable-2.9 +# - stable-2.10 +# - stable-2.11 +# - stable-2.12 +# - devel +# runs-on: ubuntu-latest +# steps: - - name: Check out code - uses: actions/checkout@v2 +# - name: Check out code +# uses: actions/checkout@v2 - - name: Perform sanity testing with ansible-test - uses: ansible-community/ansible-test-gh-action@release/v1 - with: - ansible-core-version: ${{ matrix.ansible }} - testing-type: sanity +# - name: Perform sanity testing with ansible-test +# uses: ansible-community/ansible-test-gh-action@release/v1 +# with: +# ansible-core-version: ${{ matrix.ansible }} +# testing-type: sanity - units: - runs-on: ubuntu-latest - name: Units (Ⓐ${{ matrix.ansible }}+py${{ matrix.python }}) - strategy: - # As soon as the first unit test fails, cancel the others to free up the CI queue - fail-fast: true - matrix: - ansible: - - stable-2.9 # Only if your collection supports Ansible 2.9 - - stable-2.10 - - stable-2.11 - - stable-2.12 - - devel - python: - - 2.6 - - 2.7 - - 3.5 - - 3.6 - - 3.7 - - 3.8 - - 3.9 - exclude: - # Because ansible-test doesn't support python3.9 for Ansible 2.9 - - ansible: stable-2.9 - python: 3.9 - - ansible: devel - python: 2.6 +# units: +# runs-on: ubuntu-latest +# name: Units (Ⓐ${{ matrix.ansible }}+py${{ matrix.python }}) +# strategy: +# # As soon as the first unit test fails, cancel the others to free up the CI queue +# fail-fast: true +# matrix: +# ansible: +# - stable-2.9 # Only if your collection supports Ansible 2.9 +# - stable-2.10 +# - stable-2.11 +# - stable-2.12 +# - devel +# python: +# - 2.6 +# - 2.7 +# - 3.5 +# - 3.6 +# - 3.7 +# - 3.8 +# - 3.9 +# exclude: +# # Because ansible-test doesn't support python3.9 for Ansible 2.9 +# - ansible: stable-2.9 +# python: 3.9 +# - ansible: devel +# python: 2.6 - steps: - - name: Check out code - uses: actions/checkout@v2 +# steps: +# - name: Check out code +# uses: actions/checkout@v2 - - name: Perform unit testing with ansible-test - uses: ansible-community/ansible-test-gh-action@release/v1 - with: - ansible-core-version: ${{ matrix.ansible }} - target-python-version: ${{ matrix.python }} - python-version: 3.8 - testing-type: units - test-deps: >- - ansible.netcommon - ansible.utils +# - name: Perform unit testing with ansible-test +# uses: ansible-community/ansible-test-gh-action@release/v1 +# with: +# ansible-core-version: ${{ matrix.ansible }} +# target-python-version: ${{ matrix.python }} +# python-version: 3.8 +# testing-type: units +# test-deps: >- +# ansible.netcommon +# ansible.utils -# Please consult the Readme for information on why we disabled integration tests temporarily. +# # Please consult the Readme for information on why we disabled integration tests temporarily. - # integration: - # runs-on: ubuntu-latest - # name: I (Ⓐ${{ matrix.ansible }}+py${{ matrix.python }}) - # strategy: - # fail-fast: false - # matrix: - # ansible: - # - stable-2.9 # Only if your collection supports Ansible 2.9 - # - stable-2.10 - # - stable-2.11 - # - stable-2.12 - # - devel - # python: - # - 2.6 - # - 2.7 - # - 3.5 - # - 3.6 - # - 3.7 - # - 3.8 - # - 3.9 - # exclude: - # # Because ansible-test doesn't support python3.9 for Ansible 2.9 - # - ansible: stable-2.9 - # python: 3.9 - # - ansible: devel - # python: 2.6 +# # integration: +# # runs-on: ubuntu-latest +# # name: I (Ⓐ${{ matrix.ansible }}+py${{ matrix.python }}) +# # strategy: +# # fail-fast: false +# # matrix: +# # ansible: +# # - stable-2.9 # Only if your collection supports Ansible 2.9 +# # - stable-2.10 +# # - stable-2.11 +# # - stable-2.12 +# # - devel +# # python: +# # - 2.6 +# # - 2.7 +# # - 3.5 +# # - 3.6 +# # - 3.7 +# # - 3.8 +# # - 3.9 +# # exclude: +# # # Because ansible-test doesn't support python3.9 for Ansible 2.9 +# # - ansible: stable-2.9 +# # python: 3.9 +# # - ansible: devel +# # python: 2.6 - # steps: - # - name: Check out code - # uses: actions/checkout@v2 +# # steps: +# # - name: Check out code +# # uses: actions/checkout@v2 - # - name: Perform integration testing with ansible-test - # uses: ansible-community/ansible-test-gh-action@release/v1 - # with: - # ansible-core-version: ${{ matrix.ansible }} - # python-version: 3.8 - # pre-test-cmd: >- - # mkdir -p tests/output/ - # touch tests/output/coverage - # target-python-version: ${{ matrix.python }} - # testing-type: integration - # test-deps: >- - # ansible.netcommon - # ansible.utils +# # - name: Perform integration testing with ansible-test +# # uses: ansible-community/ansible-test-gh-action@release/v1 +# # with: +# # ansible-core-version: ${{ matrix.ansible }} +# # python-version: 3.8 +# # pre-test-cmd: >- +# # mkdir -p tests/output/ +# # touch tests/output/coverage +# # target-python-version: ${{ matrix.python }} +# # testing-type: integration +# # test-deps: >- +# # ansible.netcommon +# # ansible.utils diff --git a/ansible_collections/community/sap/CHANGELOG.rst b/ansible_collections/community/sap/CHANGELOG.rst index 2662ad232..714ed15a5 100644 --- a/ansible_collections/community/sap/CHANGELOG.rst +++ b/ansible_collections/community/sap/CHANGELOG.rst @@ -5,15 +5,37 @@ Community SAP Release Notes .. contents:: Topics +v2.0.0 +====== + +Release Summary +--------------- + +This release deprecates all modules and redirect them to community.sap_libs. The modules are removed in this release. +The modules are available in the community.sap_libs repository. + +Major Changes +------------- + +- all modules - everything is now a redirect to the new collection community.sap_libs + +Deprecated Features +------------------- + +- community.sap.hana_query - is deprecated in favor of community.sap_libs.sap_hdbsql +- community.sap.sap_company - is deprecated in favor of community.sap_libs.sap_company +- community.sap.sap_snote - is deprecated in favor of community.sap_libs.sap_snote +- community.sap.sap_task_list_execute - is deprecated in favor of community.sap_libs.sap_task_list_execute +- community.sap.sap_user - is deprecated in favor of community.sap_libs.sap_user +- community.sap.sapcar_extract - is deprecated in favor of community.sap_libs.sapcar_extract + v1.0.0 ====== Release Summary --------------- -This is the fir major release of the ``community.sap`` collection. -This changelog contains all changes to the modules and plugins in this collection -that have been made after the previous release. +This is the first major release of the ``community.sap`` collection. This changelog contains all changes to the modules and plugins in this collection that have been made after the previous release. Minor Changes ------------- @@ -26,14 +48,14 @@ New Modules Identity ~~~~~~~~ -- identity.sap_company - This module will manage a company entities in a SAP S4HANA environment -- identity.sap_user - This module will manage a user entities in a SAP S4/HANA environment +- sap_company - This module will manage a company entities in a SAP S4HANA environment +- sap_user - This module will manage a user entities in a SAP S4/HANA environment System ~~~~~~ -- system.sap_snote - This module will upload and (de)implements C(SNOTES) in a SAP S4HANA environment. -- system.sap_system_facts - Gathers SAP facts in a host +- sap_snote - This module will upload and (de)implements C(SNOTES) in a SAP S4HANA environment. +- sap_system_facts - Gathers SAP facts in a host v0.1.0 ====== @@ -52,14 +74,14 @@ Database saphana ^^^^^^^ -- database.saphana.hana_query - Execute SQL on HANA +- hana_query - Execute SQL on HANA Files ~~~~~ -- files.sapcar_extract - Manages SAP SAPCAR archives +- sapcar_extract - Manages SAP SAPCAR archives System ~~~~~~ -- system.sap_task_list_execute - Perform SAP Task list execution +- sap_task_list_execute - Perform SAP Task list execution diff --git a/ansible_collections/community/sap/FILES.json b/ansible_collections/community/sap/FILES.json index 94f9d13cb..05e702336 100644 --- a/ansible_collections/community/sap/FILES.json +++ b/ansible_collections/community/sap/FILES.json @@ -60,7 +60,7 @@ "name": ".github/workflows/ansible-test.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "b33230275f011323f420a5c0bac294a83590804750a1895e78ab9d8f0e89e874", + "chksum_sha256": "141fb2c403baf2847bf06f9281f397e22fc5325262ef017cace4bde09d6f803d", "format": 1 }, { @@ -102,14 +102,14 @@ "name": "changelogs/changelog.yaml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "6638411429b43df9657c1fda5c88510094303f9f58b929c5676f66fac72b8d4c", + "chksum_sha256": "d58ffee3cafd91ae2cebaa92a66100609fcf1a19501b2e00c1d5b93d0bbc7fcb", "format": 1 }, { "name": "changelogs/config.yaml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "60799a00c74a20f69eadcfd8e4fa218bf3d118cc3d6bc2e538ff6efb47760d00", + "chksum_sha256": "5f253a9432287fcdfe3100b556bf39d442a5e8b5a5fd3ec4a971f37f954ebac0", "format": 1 }, { @@ -123,7 +123,7 @@ "name": "meta/runtime.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "df18179bb2f5447a56ac92261a911649b96821c0b2c08eea62d5cc6b0195203f", + "chksum_sha256": "9a8c86337928225fea4abd7361f2813f48b1770c4ae83aac940e7b491a4e143a", "format": 1 }, { @@ -169,136 +169,10 @@ "format": 1 }, { - "name": "plugins/modules/hana_query.py", + "name": "plugins/modules/__init__.py", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "44ffd7642f1285a808a04bb7772a1869c4a0075a049c6370f98c53c5581ad8b6", - "format": 1 - }, - { - "name": "plugins/modules/sap_company.py", - "ftype": "file", - "chksum_type": "sha256", - "chksum_sha256": "daf9bd3a40aba75148729b1b10fd4c4d0a320d6660228bce8d7c1cd90c6bf5e8", - "format": 1 - }, - { - "name": "plugins/modules/sap_snote.py", - "ftype": "file", - "chksum_type": "sha256", - "chksum_sha256": "52b12cacc618430f176efc1cd91021bf83e74ed9f4d2febf7f1200241fb559bb", - "format": 1 - }, - { - "name": "plugins/modules/sap_system_facts.py", - "ftype": "file", - "chksum_type": "sha256", - "chksum_sha256": "def5406922e38fb12999ebd2463bf3e560dd2cc7b6052c63426b4277e2963b23", - "format": 1 - }, - { - "name": "plugins/modules/sap_task_list_execute.py", - "ftype": "file", - "chksum_type": "sha256", - "chksum_sha256": "62052a6017278b4bc1d22bad9f0638f4fc78f5b2ba7de72870fa5de5cf15c96c", - "format": 1 - }, - { - "name": "plugins/modules/sap_user.py", - "ftype": "file", - "chksum_type": "sha256", - "chksum_sha256": "73079c029034e5d047231f06b0302d362c23b494448a856011bad7a2d93abd62", - "format": 1 - }, - { - "name": "plugins/modules/sapcar_extract.py", - "ftype": "file", - "chksum_type": "sha256", - "chksum_sha256": "52a51f17cd9f0ffd5ddeb63d2c397526db7ced2c78fc3008385e9ca00659ae72", - "format": 1 - }, - { - "name": "plugins/modules/database", - "ftype": "dir", - "chksum_type": null, - "chksum_sha256": null, - "format": 1 - }, - { - "name": "plugins/modules/database/saphana", - "ftype": "dir", - "chksum_type": null, - "chksum_sha256": null, - "format": 1 - }, - { - "name": "plugins/modules/database/saphana/hana_query.py", - "ftype": "file", - "chksum_type": "sha256", - "chksum_sha256": "44ffd7642f1285a808a04bb7772a1869c4a0075a049c6370f98c53c5581ad8b6", - "format": 1 - }, - { - "name": "plugins/modules/files", - "ftype": "dir", - "chksum_type": null, - "chksum_sha256": null, - "format": 1 - }, - { - "name": "plugins/modules/files/sapcar_extract.py", - "ftype": "file", - "chksum_type": "sha256", - "chksum_sha256": "52a51f17cd9f0ffd5ddeb63d2c397526db7ced2c78fc3008385e9ca00659ae72", - "format": 1 - }, - { - "name": "plugins/modules/identity", - "ftype": "dir", - "chksum_type": null, - "chksum_sha256": null, - "format": 1 - }, - { - "name": "plugins/modules/identity/sap_company.py", - "ftype": "file", - "chksum_type": "sha256", - "chksum_sha256": "daf9bd3a40aba75148729b1b10fd4c4d0a320d6660228bce8d7c1cd90c6bf5e8", - "format": 1 - }, - { - "name": "plugins/modules/identity/sap_user.py", - "ftype": "file", - "chksum_type": "sha256", - "chksum_sha256": "73079c029034e5d047231f06b0302d362c23b494448a856011bad7a2d93abd62", - "format": 1 - }, - { - "name": "plugins/modules/system", - "ftype": "dir", - "chksum_type": null, - "chksum_sha256": null, - "format": 1 - }, - { - "name": "plugins/modules/system/sap_snote.py", - "ftype": "file", - "chksum_type": "sha256", - "chksum_sha256": "52b12cacc618430f176efc1cd91021bf83e74ed9f4d2febf7f1200241fb559bb", - "format": 1 - }, - { - "name": "plugins/modules/system/sap_system_facts.py", - "ftype": "file", - "chksum_type": "sha256", - "chksum_sha256": "def5406922e38fb12999ebd2463bf3e560dd2cc7b6052c63426b4277e2963b23", - "format": 1 - }, - { - "name": "plugins/modules/system/sap_task_list_execute.py", - "ftype": "file", - "chksum_type": "sha256", - "chksum_sha256": "62052a6017278b4bc1d22bad9f0638f4fc78f5b2ba7de72870fa5de5cf15c96c", + "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "format": 1 }, { @@ -606,7 +480,7 @@ "name": "CHANGELOG.rst", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "96de6ff24a33521295f40c708f78bd801ce7a7cf5756a2982e292fc8de826d5e", + "chksum_sha256": "63e3ec595a36659d4977981c1abfd3c8efb0fe2eace862746feabe968e13ba3f", "format": 1 }, { @@ -648,7 +522,7 @@ "name": "README.md", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "241e90547fb638d794abf998542e9e72675b4ce97ed1e3ff223267f195818a63", + "chksum_sha256": "d600b5ca720d33e93ee89c9bdfba410c8f7dc435fa29ea7ca4ebfa3159f4311b", "format": 1 }, { diff --git a/ansible_collections/community/sap/MANIFEST.json b/ansible_collections/community/sap/MANIFEST.json index b03f312a2..5385f2f71 100644 --- a/ansible_collections/community/sap/MANIFEST.json +++ b/ansible_collections/community/sap/MANIFEST.json @@ -2,7 +2,7 @@ "collection_info": { "namespace": "community", "name": "sap", - "version": "1.0.0", + "version": "2.0.0", "authors": [ "Rainer Leber (github.com/rainerleber)", "Robert Kraemer (github.com/rkpobe)" @@ -14,9 +14,11 @@ "description": "SAP community collection for Ansible", "license": [], "license_file": "LICENSE", - "dependencies": {}, + "dependencies": { + "community.sap_libs": ">=1.0.0" + }, "repository": "https://github.com/ansible-collections/community.sap", - "documentation": "https://github.com/ansible-collection/community.sap/tree/main/docs", + "documentation": "https://github.com/ansible-collection/community.sap", "homepage": "https://github.com/ansible-collections/community.sap", "issues": "https://github.com/ansible-collections/community.sap/issues" }, @@ -24,7 +26,7 @@ "name": "FILES.json", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "37274fcb06645cec88067238f9d976cb36d1a807453950618d6f8537de8483bc", + "chksum_sha256": "90eb59f365d6576a46b04852a21d5998d4ad14dcbb20ae1547d5a1667dcda9d9", "format": 1 }, "format": 1 diff --git a/ansible_collections/community/sap/README.md b/ansible_collections/community/sap/README.md index 84940afce..dd935b270 100644 --- a/ansible_collections/community/sap/README.md +++ b/ansible_collections/community/sap/README.md @@ -1,5 +1,11 @@ -# Community SAP Collection +# Deprecated Community SAP Collection +# **WARNING: This collection is deprecated, not maintained anymore and superseded by the collection [**community.sap_libs**](https://github.com/sap-linuxlab/community.sap_libs)** + +**Feel free to raise issues at the new place. +All CI tests are disabled.** + +--- This repository contains the community.sap Ansible Collection. The collection includes modules and plugins supported by the Ansible SAP community to help SAP landscape management. # SAP Collection for Ansible diff --git a/ansible_collections/community/sap/changelogs/changelog.yaml b/ansible_collections/community/sap/changelogs/changelog.yaml index bfa4aa056..39f79a298 100644 --- a/ansible_collections/community/sap/changelogs/changelog.yaml +++ b/ansible_collections/community/sap/changelogs/changelog.yaml @@ -21,9 +21,9 @@ releases: changes: minor_changes: - sapcar_extract.py - more strict logic for filenames - release_summary: 'This is the first major release of the ``community.sap`` collection. + release_summary: This is the first major release of the ``community.sap`` collection. This changelog contains all changes to the modules and plugins in this collection - that have been made after the previous release.' + that have been made after the previous release. fragments: - 1.0.0.yml - 11-filenamesuffixcheck.yml @@ -42,3 +42,22 @@ releases: name: sap_user namespace: identity release_date: '2022-02-17' + 2.0.0: + changes: + deprecated_features: + - community.sap.hana_query - is deprecated in favor of community.sap_libs.sap_hdbsql + - community.sap.sap_company - is deprecated in favor of community.sap_libs.sap_company + - community.sap.sap_snote - is deprecated in favor of community.sap_libs.sap_snote + - community.sap.sap_task_list_execute - is deprecated in favor of community.sap_libs.sap_task_list_execute + - community.sap.sap_user - is deprecated in favor of community.sap_libs.sap_user + - community.sap.sapcar_extract - is deprecated in favor of community.sap_libs.sapcar_extract + major_changes: + - all modules - everything is now a redirect to the new collection community.sap_libs + release_summary: 'This release deprecates all modules and redirect them to community.sap_libs. + The modules are removed in this release. + + The modules are available in the community.sap_libs repository.' + fragments: + - 0029-deprecation.yml + - 2.0.0.yml + release_date: '2023-07-14' diff --git a/ansible_collections/community/sap/changelogs/config.yaml b/ansible_collections/community/sap/changelogs/config.yaml index 76c44c97e..db443763c 100644 --- a/ansible_collections/community/sap/changelogs/config.yaml +++ b/ansible_collections/community/sap/changelogs/config.yaml @@ -4,6 +4,7 @@ changes_file: changelog.yaml changes_format: combined keep_fragments: false mention_ancestor: true +flatmap: true new_plugins_after_name: removed_features notesdir: fragments prelude_section_name: release_summary diff --git a/ansible_collections/community/sap/meta/runtime.yml b/ansible_collections/community/sap/meta/runtime.yml index 2ee3c9fa9..15cbcba59 100644 --- a/ansible_collections/community/sap/meta/runtime.yml +++ b/ansible_collections/community/sap/meta/runtime.yml @@ -1,2 +1,33 @@ --- requires_ansible: '>=2.9.10' + +plugin_routing: + modules: + community.sap.hana_query: + redirect: community.sap_libs.sap_hdbsql + deprecation: + warning_text: Use community.sap_libs.sap_hdbsql instead. + community.sap.sap_company: + redirect: community.sap_libs.sap_company + deprecation: + warning_text: Use community.sap_libs.sap_company instead. + community.sap.sap_snote: + redirect: community.sap_libs.sap_snote + deprecation: + warning_text: Use community.sap_libs.sap_snote instead. + community.sap.sap_snote: + redirect: community.sap_libs.sap_system_facts + deprecation: + warning_text: Use community.sap_libs.sap_system_facts instead. + community.sap.sap_user: + redirect: community.sap_libs.sap_user + deprecation: + warning_text: Use community.sap_libs.sap_user instead. + community.sap.sap_task_list_execute: + redirect: community.sap_libs.sap_task_list_execute + deprecation: + warning_text: Use community.sap_libs.sap_task_list_execute instead. + community.sap.sapcar_extract: + redirect: community.sap_libs.sapcar_extract + deprecation: + warning_text: Use community.sap_libs.sapcar_extract instead. diff --git a/ansible_collections/community/sap/plugins/modules/__init__.py b/ansible_collections/community/sap/plugins/modules/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/ansible_collections/community/sap/plugins/modules/__init__.py diff --git a/ansible_collections/community/sap/plugins/modules/database/saphana/hana_query.py b/ansible_collections/community/sap/plugins/modules/database/saphana/hana_query.py deleted file mode 100644 index 9eb43db09..000000000 --- a/ansible_collections/community/sap/plugins/modules/database/saphana/hana_query.py +++ /dev/null @@ -1,238 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: (c) 2021, Rainer Leber <rainerleber@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: hana_query -short_description: Execute SQL on HANA -version_added: "0.1.0" -description: This module executes SQL statements on HANA with hdbsql. -options: - sid: - description: The system ID. - type: str - required: false - bin_path: - description: The path to the hdbsql binary. - type: str - required: false - instance: - description: The instance number. - type: str - required: true - user: - description: A dedicated username. The user could be also in hdbuserstore. - type: str - default: SYSTEM - userstore: - description: If C(true), the user must be in hdbuserstore. - type: bool - default: false - password: - description: - - The password to connect to the database. - - "B(Note:) Since the passwords have to be passed as command line arguments, I(userstore=true) should - be used whenever possible, as command line arguments can be seen by other users - on the same machine." - type: str - autocommit: - description: Autocommit the statement. - type: bool - default: true - host: - description: The Host IP address. The port can be defined as well. - type: str - database: - description: Define the database on which to connect. - type: str - encrypted: - description: Use encrypted connection. - type: bool - default: false - filepath: - description: - - One or more files each containing one SQL query to run. - - Must be a string or list containing strings. - type: list - elements: path - query: - description: - - SQL query to run. - - Must be a string or list containing strings. Please note that if you supply a string, it will be split by commas (C(,)) to a list. - It is better to supply a one-element list instead to avoid mangled input. - type: list - elements: str -notes: - - Does not support C(check_mode). Always reports that the state has changed even if no changes have been made. -author: - - Rainer Leber (@rainerleber) -''' - -EXAMPLES = r''' -- name: Simple select query - community.sap.hana_query: - sid: "hdb" - instance: "01" - password: "Test123" - query: select user_name from users - -- name: RUN select query with host port - community.sap.hana_query: - sid: "hdb" - instance: "01" - password: "Test123" - host: "10.10.2.4:30001" - query: select user_name from users - -- name: Run several queries - community.sap.hana_query: - sid: "hdb" - instance: "01" - password: "Test123" - query: - - select user_name from users - - select * from SYSTEM - host: "localhost" - autocommit: False - -- name: Run several queries with path - community.sap.hana_query: - bin_path: "/usr/sap/HDB/HDB01/exe/hdbsql" - instance: "01" - password: "Test123" - query: - - select user_name from users - - select * from users - host: "localhost" - autocommit: False - -- name: Run several queries from file - community.sap.hana_query: - sid: "hdb" - instance: "01" - password: "Test123" - filepath: - - /tmp/HANA_CPU_UtilizationPerCore_2.00.020+.txt - - /tmp/HANA.txt - host: "localhost" - -- name: Run several queries from user store - community.sap.hana_query: - sid: "hdb" - instance: "01" - user: hdbstoreuser - userstore: true - query: - - select user_name from users - - select * from users - autocommit: False -''' - -RETURN = r''' -query_result: - description: List containing results of all queries executed (one sublist for every query). - returned: on success - type: list - elements: list - sample: [[{"Column": "Value1"}, {"Column": "Value2"}], [{"Column": "Value1"}, {"Column": "Value2"}]] -''' - -import csv -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.six import StringIO -from ansible.module_utils.common.text.converters import to_native - - -def csv_to_list(rawcsv): - reader_raw = csv.DictReader(StringIO(rawcsv)) - reader = [dict((k, v.strip()) for k, v in row.items()) for row in reader_raw] - return list(reader) - - -def main(): - module = AnsibleModule( - argument_spec=dict( - sid=dict(type='str', required=False), - bin_path=dict(type='str', required=False), - instance=dict(type='str', required=True), - encrypted=dict(type='bool', default=False), - host=dict(type='str', required=False), - user=dict(type='str', default="SYSTEM"), - userstore=dict(type='bool', default=False), - password=dict(type='str', no_log=True), - database=dict(type='str', required=False), - query=dict(type='list', elements='str', required=False), - filepath=dict(type='list', elements='path', required=False), - autocommit=dict(type='bool', default=True), - ), - required_one_of=[('query', 'filepath'), ('sid', 'instance')], - required_if=[('userstore', False, ['password'])], - supports_check_mode=False, - ) - rc, out, err, out_raw = [0, [], "", ""] - - params = module.params - - sid = params['sid'] - bin_path = params['bin_path'] - instance = params['instance'] - user = params['user'] - userstore = params['userstore'] - password = params['password'] - autocommit = params['autocommit'] - host = params['host'] - database = params['database'] - encrypted = params['encrypted'] - - filepath = params['filepath'] - query = params['query'] - - if bin_path is None: - bin_path = "/usr/sap/{sid}/HDB{instance}/exe/hdbsql".format(sid=sid.upper(), instance=instance) - - try: - command = [module.get_bin_path(bin_path, required=True)] - except Exception as e: - module.fail_json(msg='Failed to find hdbsql at the expected path "{0}".Please check SID and instance number: "{1}"'.format(bin_path, to_native(e))) - - if encrypted is True: - command.extend(['-attemptencrypt']) - if autocommit is False: - command.extend(['-z']) - if host is not None: - command.extend(['-n', host]) - if database is not None: - command.extend(['-d', database]) - # -x Suppresses additional output, such as the number of selected rows in a result set. - if userstore: - command.extend(['-x', '-U', user]) - else: - command.extend(['-x', '-i', instance, '-u', user, '-p', password]) - - if filepath is not None: - command.extend(['-I']) - for p in filepath: - # makes a command like hdbsql -i 01 -u SYSTEM -p secret123# -I /tmp/HANA_CPU_UtilizationPerCore_2.00.020+.txt, - # iterates through files and append the output to var out. - query_command = command + [p] - (rc, out_raw, err) = module.run_command(query_command) - out.append(csv_to_list(out_raw)) - if query is not None: - for q in query: - # makes a command like hdbsql -i 01 -u SYSTEM -p secret123# "select user_name from users", - # iterates through multiple commands and append the output to var out. - query_command = command + [q] - (rc, out_raw, err) = module.run_command(query_command) - out.append(csv_to_list(out_raw)) - changed = True - - module.exit_json(changed=changed, rc=rc, query_result=out, stderr=err) - - -if __name__ == '__main__': - main() diff --git a/ansible_collections/community/sap/plugins/modules/files/sapcar_extract.py b/ansible_collections/community/sap/plugins/modules/files/sapcar_extract.py deleted file mode 100644 index d586dd330..000000000 --- a/ansible_collections/community/sap/plugins/modules/files/sapcar_extract.py +++ /dev/null @@ -1,220 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: (c) 2021, Rainer Leber <rainerleber@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: sapcar_extract -short_description: Manages SAP SAPCAR archives -version_added: "0.1.0" -description: - - Provides support for unpacking C(sar)/C(car) files with the SAPCAR binary from SAP and pulling - information back into Ansible. -options: - path: - description: The path to the SAR/CAR file. - type: path - required: true - dest: - description: - - The destination where SAPCAR extracts the SAR file. Missing folders will be created. - If this parameter is not provided, it will unpack in the same folder as the SAR file. - type: path - binary_path: - description: - - The path to the SAPCAR binary, for example, C(/home/dummy/sapcar) or C(https://myserver/SAPCAR). - If this parameter is not provided, the module will look in C(PATH). - type: path - signature: - description: - - If C(true), the signature will be extracted. - default: false - type: bool - security_library: - description: - - The path to the security library, for example, C(/usr/sap/hostctrl/exe/libsapcrytp.so), for signature operations. - type: path - manifest: - description: - - The name of the manifest. - default: "SIGNATURE.SMF" - type: str - remove: - description: - - If C(true), the SAR/CAR file will be removed. B(This should be used with caution!) - default: false - type: bool -author: - - Rainer Leber (@RainerLeber) -notes: - - Always returns C(changed=true) in C(check_mode). -''' - -EXAMPLES = r""" -- name: Extract SAR file - community.sap.sapcar_extract: - path: "~/source/hana.sar" - -- name: Extract SAR file with destination - community.sap.sapcar_extract: - path: "~/source/hana.sar" - dest: "~/test/" - -- name: Extract SAR file with destination and download from webserver can be a fileshare as well - community.sap.sapcar_extract: - path: "~/source/hana.sar" - dest: "~/dest/" - binary_path: "https://myserver/SAPCAR" - -- name: Extract SAR file and delete SAR after extract - community.sap.sapcar_extract: - path: "~/source/hana.sar" - remove: true - -- name: Extract SAR file with manifest - community.sap.sapcar_extract: - path: "~/source/hana.sar" - signature: true - -- name: Extract SAR file with manifest and rename it - community.sap.sapcar_extract: - path: "~/source/hana.sar" - manifest: "MyNewSignature.SMF" - signature: true -""" - -import os -from tempfile import NamedTemporaryFile -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.urls import open_url -from ansible.module_utils.common.text.converters import to_native - - -def get_list_of_files(dir_name): - # create a list of file and directories - # names in the given directory - list_of_file = os.listdir(dir_name) - allFiles = list() - # Iterate over all the entries - for entry in list_of_file: - # Create full path - fullPath = os.path.join(dir_name, entry) - # If entry is a directory then get the list of files in this directory - if os.path.isdir(fullPath): - allFiles = allFiles + [fullPath] - allFiles = allFiles + get_list_of_files(fullPath) - else: - allFiles.append(fullPath) - return allFiles - - -def download_SAPCAR(binary_path, module): - bin_path = None - # download sapcar binary if url is provided otherwise path is returned - if binary_path is not None: - if binary_path.startswith('https://') or binary_path.startswith('http://'): - random_file = NamedTemporaryFile(delete=False) - with open_url(binary_path) as response: - with random_file as out_file: - data = response.read() - out_file.write(data) - os.chmod(out_file.name, 0o700) - bin_path = out_file.name - module.add_cleanup_file(bin_path) - else: - bin_path = binary_path - return bin_path - - -def check_if_present(command, path, dest, signature, manifest, module): - # manipulating output from SAR file for compare with already extracted files - iter_command = [command, '-tvf', path] - sar_out = module.run_command(iter_command)[1] - sar_raw = sar_out.split("\n")[1:] - if dest[-1] != "/": - dest = dest + "/" - sar_files = [dest + x.split(" ")[-1] for x in sar_raw if x] - # remove any SIGNATURE.SMF from list because it will not unpacked if signature is false - if not signature: - sar_files = [item for item in sar_files if not item.endswith('.SMF')] - # if signature is renamed manipulate files in list of sar file for compare. - if manifest != "SIGNATURE.SMF": - sar_files = [item for item in sar_files if not item.endswith('.SMF')] - sar_files = sar_files + [manifest] - # get extracted files if present - files_extracted = get_list_of_files(dest) - # compare extracted files with files in sar file - present = all(elem in files_extracted for elem in sar_files) - return present - - -def main(): - module = AnsibleModule( - argument_spec=dict( - path=dict(type='path', required=True), - dest=dict(type='path'), - binary_path=dict(type='path'), - signature=dict(type='bool', default=False), - security_library=dict(type='path'), - manifest=dict(type='str', default="SIGNATURE.SMF"), - remove=dict(type='bool', default=False), - ), - supports_check_mode=True, - ) - rc, out, err = [0, "", ""] - params = module.params - check_mode = module.check_mode - - path = params['path'] - dest = params['dest'] - signature = params['signature'] - security_library = params['security_library'] - manifest = params['manifest'] - remove = params['remove'] - - bin_path = download_SAPCAR(params['binary_path'], module) - - if dest is None: - dest_head_tail = os.path.split(path) - dest = dest_head_tail[0] + '/' - else: - if not os.path.exists(dest): - os.makedirs(dest, 0o755) - - if bin_path is not None: - command = [module.get_bin_path(bin_path, required=True)] - else: - try: - command = [module.get_bin_path('sapcar', required=True)] - except Exception as e: - module.fail_json(msg='Failed to find SAPCAR at the expected path or URL "{0}". Please check whether it is available: {1}' - .format(bin_path, to_native(e))) - - present = check_if_present(command[0], path, dest, signature, manifest, module) - - if not present: - command.extend(['-xvf', path, '-R', dest]) - if security_library: - command.extend(['-L', security_library]) - if signature: - command.extend(['-manifest', manifest]) - if not check_mode: - (rc, out, err) = module.run_command(command, check_rc=True) - changed = True - else: - changed = False - out = "already unpacked" - - if remove: - os.remove(path) - - module.exit_json(changed=changed, message=rc, stdout=out, - stderr=err, command=' '.join(command)) - - -if __name__ == '__main__': - main() diff --git a/ansible_collections/community/sap/plugins/modules/hana_query.py b/ansible_collections/community/sap/plugins/modules/hana_query.py deleted file mode 100644 index 9eb43db09..000000000 --- a/ansible_collections/community/sap/plugins/modules/hana_query.py +++ /dev/null @@ -1,238 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: (c) 2021, Rainer Leber <rainerleber@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: hana_query -short_description: Execute SQL on HANA -version_added: "0.1.0" -description: This module executes SQL statements on HANA with hdbsql. -options: - sid: - description: The system ID. - type: str - required: false - bin_path: - description: The path to the hdbsql binary. - type: str - required: false - instance: - description: The instance number. - type: str - required: true - user: - description: A dedicated username. The user could be also in hdbuserstore. - type: str - default: SYSTEM - userstore: - description: If C(true), the user must be in hdbuserstore. - type: bool - default: false - password: - description: - - The password to connect to the database. - - "B(Note:) Since the passwords have to be passed as command line arguments, I(userstore=true) should - be used whenever possible, as command line arguments can be seen by other users - on the same machine." - type: str - autocommit: - description: Autocommit the statement. - type: bool - default: true - host: - description: The Host IP address. The port can be defined as well. - type: str - database: - description: Define the database on which to connect. - type: str - encrypted: - description: Use encrypted connection. - type: bool - default: false - filepath: - description: - - One or more files each containing one SQL query to run. - - Must be a string or list containing strings. - type: list - elements: path - query: - description: - - SQL query to run. - - Must be a string or list containing strings. Please note that if you supply a string, it will be split by commas (C(,)) to a list. - It is better to supply a one-element list instead to avoid mangled input. - type: list - elements: str -notes: - - Does not support C(check_mode). Always reports that the state has changed even if no changes have been made. -author: - - Rainer Leber (@rainerleber) -''' - -EXAMPLES = r''' -- name: Simple select query - community.sap.hana_query: - sid: "hdb" - instance: "01" - password: "Test123" - query: select user_name from users - -- name: RUN select query with host port - community.sap.hana_query: - sid: "hdb" - instance: "01" - password: "Test123" - host: "10.10.2.4:30001" - query: select user_name from users - -- name: Run several queries - community.sap.hana_query: - sid: "hdb" - instance: "01" - password: "Test123" - query: - - select user_name from users - - select * from SYSTEM - host: "localhost" - autocommit: False - -- name: Run several queries with path - community.sap.hana_query: - bin_path: "/usr/sap/HDB/HDB01/exe/hdbsql" - instance: "01" - password: "Test123" - query: - - select user_name from users - - select * from users - host: "localhost" - autocommit: False - -- name: Run several queries from file - community.sap.hana_query: - sid: "hdb" - instance: "01" - password: "Test123" - filepath: - - /tmp/HANA_CPU_UtilizationPerCore_2.00.020+.txt - - /tmp/HANA.txt - host: "localhost" - -- name: Run several queries from user store - community.sap.hana_query: - sid: "hdb" - instance: "01" - user: hdbstoreuser - userstore: true - query: - - select user_name from users - - select * from users - autocommit: False -''' - -RETURN = r''' -query_result: - description: List containing results of all queries executed (one sublist for every query). - returned: on success - type: list - elements: list - sample: [[{"Column": "Value1"}, {"Column": "Value2"}], [{"Column": "Value1"}, {"Column": "Value2"}]] -''' - -import csv -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.six import StringIO -from ansible.module_utils.common.text.converters import to_native - - -def csv_to_list(rawcsv): - reader_raw = csv.DictReader(StringIO(rawcsv)) - reader = [dict((k, v.strip()) for k, v in row.items()) for row in reader_raw] - return list(reader) - - -def main(): - module = AnsibleModule( - argument_spec=dict( - sid=dict(type='str', required=False), - bin_path=dict(type='str', required=False), - instance=dict(type='str', required=True), - encrypted=dict(type='bool', default=False), - host=dict(type='str', required=False), - user=dict(type='str', default="SYSTEM"), - userstore=dict(type='bool', default=False), - password=dict(type='str', no_log=True), - database=dict(type='str', required=False), - query=dict(type='list', elements='str', required=False), - filepath=dict(type='list', elements='path', required=False), - autocommit=dict(type='bool', default=True), - ), - required_one_of=[('query', 'filepath'), ('sid', 'instance')], - required_if=[('userstore', False, ['password'])], - supports_check_mode=False, - ) - rc, out, err, out_raw = [0, [], "", ""] - - params = module.params - - sid = params['sid'] - bin_path = params['bin_path'] - instance = params['instance'] - user = params['user'] - userstore = params['userstore'] - password = params['password'] - autocommit = params['autocommit'] - host = params['host'] - database = params['database'] - encrypted = params['encrypted'] - - filepath = params['filepath'] - query = params['query'] - - if bin_path is None: - bin_path = "/usr/sap/{sid}/HDB{instance}/exe/hdbsql".format(sid=sid.upper(), instance=instance) - - try: - command = [module.get_bin_path(bin_path, required=True)] - except Exception as e: - module.fail_json(msg='Failed to find hdbsql at the expected path "{0}".Please check SID and instance number: "{1}"'.format(bin_path, to_native(e))) - - if encrypted is True: - command.extend(['-attemptencrypt']) - if autocommit is False: - command.extend(['-z']) - if host is not None: - command.extend(['-n', host]) - if database is not None: - command.extend(['-d', database]) - # -x Suppresses additional output, such as the number of selected rows in a result set. - if userstore: - command.extend(['-x', '-U', user]) - else: - command.extend(['-x', '-i', instance, '-u', user, '-p', password]) - - if filepath is not None: - command.extend(['-I']) - for p in filepath: - # makes a command like hdbsql -i 01 -u SYSTEM -p secret123# -I /tmp/HANA_CPU_UtilizationPerCore_2.00.020+.txt, - # iterates through files and append the output to var out. - query_command = command + [p] - (rc, out_raw, err) = module.run_command(query_command) - out.append(csv_to_list(out_raw)) - if query is not None: - for q in query: - # makes a command like hdbsql -i 01 -u SYSTEM -p secret123# "select user_name from users", - # iterates through multiple commands and append the output to var out. - query_command = command + [q] - (rc, out_raw, err) = module.run_command(query_command) - out.append(csv_to_list(out_raw)) - changed = True - - module.exit_json(changed=changed, rc=rc, query_result=out, stderr=err) - - -if __name__ == '__main__': - main() diff --git a/ansible_collections/community/sap/plugins/modules/identity/sap_company.py b/ansible_collections/community/sap/plugins/modules/identity/sap_company.py deleted file mode 100644 index 8d3838e5f..000000000 --- a/ansible_collections/community/sap/plugins/modules/identity/sap_company.py +++ /dev/null @@ -1,326 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: (c) 2021, Rainer Leber <rainerleber@gmail.com> <rainer.leber@sva.de> -# 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: sap_company - -short_description: This module will manage a company entities in a SAP S4HANA environment - -version_added: "1.0.0" - -description: - - The M(community.sap.sap_user) module depends on C(pyrfc) Python library (version 2.4.0 and upwards). - Depending on distribution you are using, you may need to install additional packages to - have these available. - - This module will use the company BAPIs C(BAPI_COMPANY_CLONE) and C(BAPI_COMPANY_DELETE) to manage company entities. - -options: - state: - description: - - The decision what to do with the company. - default: 'present' - choices: - - 'present' - - 'absent' - required: false - type: str - conn_username: - description: The required username for the SAP system. - required: true - type: str - conn_password: - description: The required password for the SAP system. - required: true - type: str - host: - description: The required host for the SAP system. Can be either an FQDN or IP Address. - required: true - type: str - sysnr: - description: - - The system number of the SAP system. - - You must quote the value to ensure retaining the leading zeros. - required: false - default: '01' - type: str - client: - description: - - The client number to connect to. - - You must quote the value to ensure retaining the leading zeros. - required: false - default: '000' - type: str - company_id: - description: The company id. - required: true - type: str - name: - description: The company name. - required: false - type: str - name_2: - description: Additional company name. - required: false - type: str - country: - description: The country code for the company. For example, C('DE'). - required: false - type: str - time_zone: - description: The timezone. - required: false - type: str - city: - description: The city where the company is located. - required: false - type: str - post_code: - description: The post code from the city. - required: false - type: str - street: - description: Street where the company is located. - required: false - type: str - street_no: - description: Street number. - required: false - type: str - e_mail: - description: General E-Mail address. - required: false - type: str - -requirements: - - pyrfc >= 2.4.0 - -author: - - Rainer Leber (@rainerleber) - -notes: - - Does not support C(check_mode). -''' - -EXAMPLES = r''' -- name: Create SAP Company - community.sap.sap_company: - conn_username: 'DDIC' - conn_password: 'HECtna2021#' - host: 100.0.201.20 - sysnr: '01' - client: '000' - state: present - company_id: "Comp_ID" - name: "Test_comp" - name_2: "LTD" - country: "DE" - time_zone: "UTC" - city: "City" - post_code: "12345" - street: "test_street" - street_no: "1" - e_mail: "test@test.de" - -# pass in a message and have changed true -- name: Delete SAP Company - community.sap.sap_company: - conn_username: 'DDIC' - conn_password: 'HECtna2021#' - host: 100.0.201.20 - sysnr: '01' - client: '000' - state: absent - company_id: "Comp_ID" - name: "Test_comp" - name_2: "LTD" - country: "DE" - time_zone: "UTC" - city: "City" - post_code: "12345" - street: "test_street" - street_no: "1" - e_mail: "test@test.de" -''' - -RETURN = r''' -# These are examples of possible return values, and in general should use other names for return values. -msg: - description: A small execution description. - type: str - returned: always - sample: 'Company address COMP_ID created' -out: - description: A complete description of the executed tasks. If this is available. - type: list - elements: dict - returned: always - sample: '{ - "RETURN": [ - { - "FIELD": "", - "ID": "01", - "LOG_MSG_NO": "000000", - "LOG_NO": "", - "MESSAGE": "Company address COMP_ID created", - "MESSAGE_V1": "COMP_ID", - "MESSAGE_V2": "", - "MESSAGE_V3": "", - "MESSAGE_V4": "", - "NUMBER": "078", - "PARAMETER": "", - "ROW": 0, - "SYSTEM": "", - "TYPE": "S" - } - ] - } - }' -''' - -from ansible.module_utils.basic import AnsibleModule, missing_required_lib -import traceback -try: - from pyrfc import Connection -except ImportError: - HAS_PYRFC_LIBRARY = False - ANOTHER_LIBRARY_IMPORT_ERROR = traceback.format_exc() -else: - HAS_PYRFC_LIBRARY = True - - -def call_rfc_method(connection, method_name, kwargs): - # PyRFC call function - return connection.call(method_name, **kwargs) - - -def build_company_params(name, name_2, country, time_zone, city, post_code, street, street_no, e_mail): - # Creates RFC parameters for creating organizations - # define dicts in batch - params = dict() - # define company name - params['NAME'] = name - params['NAME_2'] = name_2 - # define location - params['COUNTRY'] = country - params['TIME_ZONE'] = time_zone - params['CITY'] = city - params['POSTL_COD1'] = post_code - params['STREET'] = street - params['STREET_NO'] = street_no - # define communication - params['E_MAIL'] = e_mail - # return dict - return params - - -def return_analysis(raw): - change = False - failed = False - msg = raw['RETURN'][0]['MESSAGE'] - for state in raw['RETURN']: - if state['TYPE'] == "E": - if state['NUMBER'] == '081': - change = False - else: - failed = True - if state['TYPE'] == "S": - if state['NUMBER'] != '079': - change = True - else: - msg = "No changes where made." - return [{"change": change}, {"failed": failed}, {"msg": msg}] - - -def run_module(): - module = AnsibleModule( - argument_spec=dict( - state=dict(default='present', choices=['absent', 'present']), - conn_username=dict(type='str', required=True), - conn_password=dict(type='str', required=True, no_log=True), - host=dict(type='str', required=True), - sysnr=dict(type='str', default="01"), - client=dict(type='str', default="000"), - company_id=dict(type='str', required=True), - name=dict(type='str', required=False), - name_2=dict(type='str', required=False), - country=dict(type='str', required=False), - time_zone=dict(type='str', required=False), - city=dict(type='str', required=False), - post_code=dict(type='str', required=False), - street=dict(type='str', required=False), - street_no=dict(type='str', required=False), - e_mail=dict(type='str', required=False), - ), - supports_check_mode=False, - ) - result = dict(changed=False, msg='', out={}) - raw = "" - - params = module.params - - state = params['state'] - conn_username = (params['conn_username']).upper() - conn_password = params['conn_password'] - host = params['host'] - sysnr = params['sysnr'] - client = params['client'] - - company_id = (params['company_id']).upper() - name = params['name'] - name_2 = params['name_2'] - country = params['country'] - time_zone = params['time_zone'] - city = params['city'] - post_code = params['post_code'] - street = params['street'] - street_no = params['street_no'] - e_mail = params['e_mail'] - - if not HAS_PYRFC_LIBRARY: - module.fail_json( - msg=missing_required_lib('pyrfc'), - exception=ANOTHER_LIBRARY_IMPORT_ERROR) - - # basic RFC connection with pyrfc - try: - conn = Connection(user=conn_username, passwd=conn_password, ashost=host, sysnr=sysnr, client=client) - except Exception as err: - result['error'] = str(err) - result['msg'] = 'Something went wrong connecting to the SAP system.' - module.fail_json(**result) - - # build parameter dict of dict - company_params = build_company_params(name, name_2, country, time_zone, city, post_code, street, street_no, e_mail) - - if state == "absent": - raw = call_rfc_method(conn, 'BAPI_COMPANY_DELETE', {'COMPANY': company_id}) - - if state == "present": - raw = call_rfc_method(conn, 'BAPI_COMPANY_CLONE', - {'METHOD': {'USMETHOD': 'COMPANY_CLONE'}, 'COMPANY': company_id, 'COMP_DATA': company_params}) - - analysed = return_analysis(raw) - - result['out'] = raw - - result['changed'] = analysed[0]['change'] - result['msg'] = analysed[2]['msg'] - - if analysed[1]['failed']: - module.fail_json(**result) - - module.exit_json(**result) - - -def main(): - run_module() - - -if __name__ == '__main__': - main() diff --git a/ansible_collections/community/sap/plugins/modules/identity/sap_user.py b/ansible_collections/community/sap/plugins/modules/identity/sap_user.py deleted file mode 100644 index f83472657..000000000 --- a/ansible_collections/community/sap/plugins/modules/identity/sap_user.py +++ /dev/null @@ -1,499 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: (c) 2021, Rainer Leber <rainerleber@gmail.com> <rainer.leber@sva.de> -# 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: sap_user -short_description: This module will manage a user entities in a SAP S4/HANA environment -version_added: "1.0.0" -description: - - The M(community.sap.sap_user) module depends on C(pyrfc) Python library (version 2.4.0 and upwards). - Depending on distribution you are using, you may need to install additional packages to - have these available. - - This module will use the following user BAPIs to manage user entities. - - C(BAPI_USER_GET_DETAIL) - - C(BAPI_USER_DELETE) - - C(BAPI_USER_CREATE1) - - C(BAPI_USER_CHANGE) - - C(BAPI_USER_ACTGROUPS_ASSIGN) - - C(BAPI_USER_PROFILES_ASSIGN) - - C(BAPI_USER_UNLOCK) - - C(BAPI_USER_LOCK) -options: - state: - description: - - The decision what to do with the user. - default: 'present' - choices: - - 'present' - - 'absent' - - 'lock' - - 'unlock' - required: false - type: str - force: - description: - - Must be C('True') if the password or type should be overwritten. - default: False - required: false - type: bool - conn_username: - description: The required username for the SAP system. - required: true - type: str - conn_password: - description: The required password for the SAP system. - required: true - type: str - host: - description: The required host for the SAP system. Can be either an FQDN or IP Address. - required: true - type: str - sysnr: - description: - - The system number of the SAP system. - - You must quote the value to ensure retaining the leading zeros. - default: '00' - type: str - client: - description: - - The client number to connect to. - - You must quote the value to ensure retaining the leading zeros. - default: '000' - type: str - username: - description: - - The username. - type: str - required: true - firstname: - description: - - The Firstname of the user in the SAP system. - type: str - required: false - lastname: - description: - - The lastname of the user in the SAP system. - type: str - required: false - email: - description: - - The email address of the user in the SAP system. - type: str - required: false - password: - description: - - The password for the user in the SAP system. - type: str - required: false - useralias: - description: - - The alias for the user in the SAP system. - type: str - required: false - user_type: - description: - - The type for the user in the SAP system. - - C('A') Dialog user, C('B') System User, C('C') Communication User, - C('S') Service User, C('L') Reference User. - - Must be in uppercase. - type: str - required: false - default: 'A' - choices: ['A', 'B', 'C', 'S', 'L'] - company: - description: - - The specific company the user belongs to. - - The company name must be available in the SAP system. - type: str - required: false - profiles: - description: - - Assign profiles to the user. - - Should be in uppercase, for example C('SAP_NEW') or C('SAP_ALL'). - type: list - elements: str - default: [''] - required: false - roles: - description: - - Assign roles to the user. - type: list - elements: str - default: [''] - required: false - -requirements: - - pyrfc >= 2.4.0 -author: - - Rainer Leber (@rainerleber) -notes: - - Does not support C(check_mode). -''' - -EXAMPLES = r''' -- name: Create SAP User - community.sap.sap_user: - conn_username: 'DDIC' - conn_password: 'Test123' - host: 192.168.1.150 - sysnr: '01' - client: '000' - state: present - username: ADMIN - firstname: first_admin - lastname: last_admin - email: admin@test.de - password: Test123456 - useralias: ADMIN - company: DEFAULT_COMPANY - roles: - - "SAP_ALL" - -- name: Force change SAP User - community.sap.sap_user: - conn_username: 'DDIC' - conn_password: 'Test123' - host: 192.168.1.150 - sysnr: '01' - client: '000' - state: present - force: true - username: ADMIN - firstname: first_admin - lastname: last_admin - email: admin@test.de - password: Test123456 - useralias: ADMIN - company: DEFAULT_COMPANY - roles: - - "SAP_ALL" - -- name: Delete SAP User - community.sap.sap_user: - conn_username: 'DDIC' - conn_password: 'Test123' - host: 192.168.1.150 - sysnr: '01' - client: '000' - state: absent - force: true - username: ADMIN - -- name: Unlock SAP User - community.sap.sap_user: - conn_username: 'DDIC' - conn_password: 'Test123' - host: 192.168.1.150 - sysnr: '01' - client: '000' - state: unlock - force: true - username: ADMIN -''' - -RETURN = r''' -msg: - description: A small execution description about the user action. - type: str - returned: always - sample: 'User ADMIN created' -out: - description: A detailed description about the user action. - type: list - elements: dict - returned: on success - sample: [...,{ - "RETURN": [ - { - "FIELD": "BNAME", - "ID": "01", - "LOG_MSG_NO": "000000", - "LOG_NO": "", - "MESSAGE": "User ADMIN created", - "MESSAGE_V1": "ADMIN", - "MESSAGE_V2": "", - "MESSAGE_V3": "", - "MESSAGE_V4": "", - "NUMBER": "102", - "PARAMETER": "", - "ROW": 0, - "SYSTEM": "", - "TYPE": "S" - } - ], - "SAPUSER_UUID_HIST": []}] -''' -from ansible.module_utils.basic import AnsibleModule, missing_required_lib -import traceback -import datetime -try: - from pyrfc import Connection -except ImportError: - HAS_PYRFC_LIBRARY = False - PYRFC_LIBRARY_IMPORT_ERROR = traceback.format_exc() -else: - HAS_PYRFC_LIBRARY = True - - -def add_to_dict(target_dict, target_key, value): - # Adds the given value to a dict as the key - # check if the given key is in the given dict yet - if target_key in target_dict: - return False - target_dict[target_key] = value - return True - - -def call_rfc_method(connection, method_name, kwargs): - # PyRFC call function - return connection.call(method_name, **kwargs) - - -def build_rfc_user_params(username, firstname, lastname, email, raw_password, - useralias, user_type, raw_company, user_change, force): - """Creates RFC parameters for Creating users""" - # define dicts in batch - params = dict() - address = dict() - password = dict() - alias = dict() - logondata = dict() - company = dict() - # for change parameters - addressx = dict() - passwordx = dict() - logondatax = dict() - companyx = dict() - # define username - add_to_dict(params, 'USERNAME', username) - # define Address - add_to_dict(address, 'FIRSTNAME', firstname) - add_to_dict(address, 'LASTNAME', lastname) - add_to_dict(address, 'E_MAIL', email) - # define Password - add_to_dict(password, 'BAPIPWD', raw_password) - # define Alias - add_to_dict(alias, 'USERALIAS', useralias) - # define LogonData - add_to_dict(logondata, 'GLTGV', datetime.date.today()) - add_to_dict(logondata, 'GLTGB', '20991231') - add_to_dict(logondata, 'USTYP', user_type) - # define company - add_to_dict(company, 'COMPANY', raw_company) - params['LOGONDATA'] = logondata - params['ADDRESS'] = address - params['COMPANY'] = company - params['ALIAS'] = alias - params['PASSWORD'] = password - # add change if user exists - if user_change and force: - add_to_dict(addressx, 'FIRSTNAME', 'X') - add_to_dict(addressx, 'LASTNAME', 'X') - add_to_dict(addressx, 'E_MAIL', 'X') - # define Password - add_to_dict(passwordx, 'BAPIPWD', 'X') - # define LogonData - add_to_dict(logondatax, 'USTYP', 'X') - # define company - add_to_dict(companyx, 'COMPANY', 'X') - params['LOGONDATAX'] = logondatax - params['ADDRESSX'] = addressx - params['COMPANYX'] = companyx - params['PASSWORDX'] = passwordx - return params - - -def user_role_assignment_build_rfc_params(roles, username): - rfc_table = [] - - for role_name in roles: - table_row = {'AGR_NAME': role_name} - - add_to_dict(table_row, 'FROM_DAT', datetime.date.today()) - add_to_dict(table_row, 'TO_DAT', '20991231') - - rfc_table.append(table_row) - - return { - 'USERNAME': username, - 'ACTIVITYGROUPS': rfc_table - } - - -def user_profile_assignment_build_rfc_params(profiles, username): - rfc_table = [] - - for profile_name in profiles: - table_row = {'BAPIPROF': profile_name} - rfc_table.append(table_row) - - return { - 'USERNAME': username, - 'PROFILES': rfc_table - } - - -def check_user(user_detail): - if len(user_detail['RETURN']) > 0: - for sub in user_detail['RETURN']: - if sub['NUMBER'] == '124': - return False - return True - - -def return_analysis(raw): - change = False - failed = False - for state in raw['RETURN']: - if state['TYPE'] == "E": - if state['NUMBER'] == '224' or state['NUMBER'] == '124': - change = False - else: - failed = True - if state['TYPE'] == "S": - if state['NUMBER'] != '029': - change = True - if state['TYPE'] == "W": - if state['NUMBER'] == '049' or state['NUMBER'] == '047': - change = True - if state['NUMBER'] == '255': - change = True - return [{"change": change}, {"failed": failed}] - - -def run_module(): - module = AnsibleModule( - argument_spec=dict( - # logical values - state=dict(default='present', choices=[ - 'absent', 'present', 'lock', 'unlock']), - force=dict(type='bool', default=False), - # values for connection - conn_username=dict(type='str', required=True), - conn_password=dict(type='str', required=True, no_log=True), - host=dict(type='str', required=True), - sysnr=dict(type='str', default="00"), - client=dict(type='str', default="000"), - # values for the new or existing user - username=dict(type='str', required=True), - firstname=dict(type='str', required=False), - lastname=dict(type='str', required=False), - email=dict(type='str', required=False), - password=dict(type='str', required=False, no_log=True), - useralias=dict(type='str', required=False), - user_type=dict(default="A", - choices=['A', 'B', 'C', 'S', 'L']), - company=dict(type='str', required=False), - # values for profile must a list - # Example ["SAP_NEW", "SAP_ALL"] - profiles=dict(type='list', elements='str', default=[""]), - # values for roles must a list - roles=dict(type='list', elements='str', default=[""]), - ), - supports_check_mode=False, - required_if=[('state', 'present', ['useralias', 'company'])] - ) - result = dict(changed=False, msg='', out='') - count = 0 - raw = "" - - params = module.params - - state = params['state'] - conn_username = (params['conn_username']).upper() - conn_password = params['conn_password'] - host = params['host'] - sysnr = params['sysnr'] - client = params['client'] - - username = (params['username']).upper() - firstname = params['firstname'] - lastname = params['lastname'] - email = params['email'] - password = params['password'] - force = params['force'] - if not params['useralias'] is None: - useralias = (params['useralias']).upper() - user_type = (params['user_type']).upper() - company = params['company'] - - profiles = params['profiles'] - roles = params['roles'] - - if not HAS_PYRFC_LIBRARY: - module.fail_json( - msg=missing_required_lib('pyrfc'), - exception=PYRFC_LIBRARY_IMPORT_ERROR) - - # basic RFC connection with pyrfc - try: - conn = Connection(user=conn_username, passwd=conn_password, ashost=host, sysnr=sysnr, client=client) - except Exception as err: - result['error'] = str(err) - result['msg'] = 'Something went wrong connecting to the SAP system.' - module.fail_json(**result) - - # user details - user_detail = call_rfc_method(conn, 'BAPI_USER_GET_DETAIL', {'USERNAME': username}) - user_exists = check_user(user_detail) - - if state == "absent": - if user_exists: - raw = call_rfc_method(conn, 'BAPI_USER_DELETE', {'USERNAME': username}) - - if state == "present": - user_params = build_rfc_user_params(username, firstname, lastname, email, password, useralias, user_type, company, user_exists, force) - if not user_exists: - raw = call_rfc_method(conn, 'BAPI_USER_CREATE1', user_params) - - if user_exists: - # check for address changes when user exists - user_no_changes = all((user_detail.get('ADDRESS')).get(k) == v for k, v in (user_params.get('ADDRESS')).items()) - if not user_no_changes or force: - raw = call_rfc_method(conn, 'BAPI_USER_CHANGE', user_params) - - call_rfc_method(conn, 'BAPI_USER_ACTGROUPS_ASSIGN', user_role_assignment_build_rfc_params(roles, username)) - - call_rfc_method(conn, 'BAPI_USER_PROFILES_ASSIGN', user_profile_assignment_build_rfc_params(profiles, username)) - - if state == "unlock": - if user_exists: - raw = call_rfc_method(conn, 'BAPI_USER_UNLOCK', {'USERNAME': username}) - - if state == "lock": - if user_exists: - raw = call_rfc_method(conn, 'BAPI_USER_LOCK', {'USERNAME': username}) - - # analyse return value - if raw != '': - analysed = return_analysis(raw) - - result['out'] = raw - - result['changed'] = analysed[0]['change'] - for msgs in raw['RETURN']: - if count > 0: - result['msg'] = result['msg'] + '\n' - result['msg'] = result['msg'] + msgs['MESSAGE'] - count = count + 1 - - if analysed[1]['failed']: - module.fail_json(**result) - else: - result['msg'] = "No changes where made." - - module.exit_json(**result) - - -def main(): - run_module() - - -if __name__ == '__main__': - main() diff --git a/ansible_collections/community/sap/plugins/modules/sap_company.py b/ansible_collections/community/sap/plugins/modules/sap_company.py deleted file mode 100644 index 8d3838e5f..000000000 --- a/ansible_collections/community/sap/plugins/modules/sap_company.py +++ /dev/null @@ -1,326 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: (c) 2021, Rainer Leber <rainerleber@gmail.com> <rainer.leber@sva.de> -# 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: sap_company - -short_description: This module will manage a company entities in a SAP S4HANA environment - -version_added: "1.0.0" - -description: - - The M(community.sap.sap_user) module depends on C(pyrfc) Python library (version 2.4.0 and upwards). - Depending on distribution you are using, you may need to install additional packages to - have these available. - - This module will use the company BAPIs C(BAPI_COMPANY_CLONE) and C(BAPI_COMPANY_DELETE) to manage company entities. - -options: - state: - description: - - The decision what to do with the company. - default: 'present' - choices: - - 'present' - - 'absent' - required: false - type: str - conn_username: - description: The required username for the SAP system. - required: true - type: str - conn_password: - description: The required password for the SAP system. - required: true - type: str - host: - description: The required host for the SAP system. Can be either an FQDN or IP Address. - required: true - type: str - sysnr: - description: - - The system number of the SAP system. - - You must quote the value to ensure retaining the leading zeros. - required: false - default: '01' - type: str - client: - description: - - The client number to connect to. - - You must quote the value to ensure retaining the leading zeros. - required: false - default: '000' - type: str - company_id: - description: The company id. - required: true - type: str - name: - description: The company name. - required: false - type: str - name_2: - description: Additional company name. - required: false - type: str - country: - description: The country code for the company. For example, C('DE'). - required: false - type: str - time_zone: - description: The timezone. - required: false - type: str - city: - description: The city where the company is located. - required: false - type: str - post_code: - description: The post code from the city. - required: false - type: str - street: - description: Street where the company is located. - required: false - type: str - street_no: - description: Street number. - required: false - type: str - e_mail: - description: General E-Mail address. - required: false - type: str - -requirements: - - pyrfc >= 2.4.0 - -author: - - Rainer Leber (@rainerleber) - -notes: - - Does not support C(check_mode). -''' - -EXAMPLES = r''' -- name: Create SAP Company - community.sap.sap_company: - conn_username: 'DDIC' - conn_password: 'HECtna2021#' - host: 100.0.201.20 - sysnr: '01' - client: '000' - state: present - company_id: "Comp_ID" - name: "Test_comp" - name_2: "LTD" - country: "DE" - time_zone: "UTC" - city: "City" - post_code: "12345" - street: "test_street" - street_no: "1" - e_mail: "test@test.de" - -# pass in a message and have changed true -- name: Delete SAP Company - community.sap.sap_company: - conn_username: 'DDIC' - conn_password: 'HECtna2021#' - host: 100.0.201.20 - sysnr: '01' - client: '000' - state: absent - company_id: "Comp_ID" - name: "Test_comp" - name_2: "LTD" - country: "DE" - time_zone: "UTC" - city: "City" - post_code: "12345" - street: "test_street" - street_no: "1" - e_mail: "test@test.de" -''' - -RETURN = r''' -# These are examples of possible return values, and in general should use other names for return values. -msg: - description: A small execution description. - type: str - returned: always - sample: 'Company address COMP_ID created' -out: - description: A complete description of the executed tasks. If this is available. - type: list - elements: dict - returned: always - sample: '{ - "RETURN": [ - { - "FIELD": "", - "ID": "01", - "LOG_MSG_NO": "000000", - "LOG_NO": "", - "MESSAGE": "Company address COMP_ID created", - "MESSAGE_V1": "COMP_ID", - "MESSAGE_V2": "", - "MESSAGE_V3": "", - "MESSAGE_V4": "", - "NUMBER": "078", - "PARAMETER": "", - "ROW": 0, - "SYSTEM": "", - "TYPE": "S" - } - ] - } - }' -''' - -from ansible.module_utils.basic import AnsibleModule, missing_required_lib -import traceback -try: - from pyrfc import Connection -except ImportError: - HAS_PYRFC_LIBRARY = False - ANOTHER_LIBRARY_IMPORT_ERROR = traceback.format_exc() -else: - HAS_PYRFC_LIBRARY = True - - -def call_rfc_method(connection, method_name, kwargs): - # PyRFC call function - return connection.call(method_name, **kwargs) - - -def build_company_params(name, name_2, country, time_zone, city, post_code, street, street_no, e_mail): - # Creates RFC parameters for creating organizations - # define dicts in batch - params = dict() - # define company name - params['NAME'] = name - params['NAME_2'] = name_2 - # define location - params['COUNTRY'] = country - params['TIME_ZONE'] = time_zone - params['CITY'] = city - params['POSTL_COD1'] = post_code - params['STREET'] = street - params['STREET_NO'] = street_no - # define communication - params['E_MAIL'] = e_mail - # return dict - return params - - -def return_analysis(raw): - change = False - failed = False - msg = raw['RETURN'][0]['MESSAGE'] - for state in raw['RETURN']: - if state['TYPE'] == "E": - if state['NUMBER'] == '081': - change = False - else: - failed = True - if state['TYPE'] == "S": - if state['NUMBER'] != '079': - change = True - else: - msg = "No changes where made." - return [{"change": change}, {"failed": failed}, {"msg": msg}] - - -def run_module(): - module = AnsibleModule( - argument_spec=dict( - state=dict(default='present', choices=['absent', 'present']), - conn_username=dict(type='str', required=True), - conn_password=dict(type='str', required=True, no_log=True), - host=dict(type='str', required=True), - sysnr=dict(type='str', default="01"), - client=dict(type='str', default="000"), - company_id=dict(type='str', required=True), - name=dict(type='str', required=False), - name_2=dict(type='str', required=False), - country=dict(type='str', required=False), - time_zone=dict(type='str', required=False), - city=dict(type='str', required=False), - post_code=dict(type='str', required=False), - street=dict(type='str', required=False), - street_no=dict(type='str', required=False), - e_mail=dict(type='str', required=False), - ), - supports_check_mode=False, - ) - result = dict(changed=False, msg='', out={}) - raw = "" - - params = module.params - - state = params['state'] - conn_username = (params['conn_username']).upper() - conn_password = params['conn_password'] - host = params['host'] - sysnr = params['sysnr'] - client = params['client'] - - company_id = (params['company_id']).upper() - name = params['name'] - name_2 = params['name_2'] - country = params['country'] - time_zone = params['time_zone'] - city = params['city'] - post_code = params['post_code'] - street = params['street'] - street_no = params['street_no'] - e_mail = params['e_mail'] - - if not HAS_PYRFC_LIBRARY: - module.fail_json( - msg=missing_required_lib('pyrfc'), - exception=ANOTHER_LIBRARY_IMPORT_ERROR) - - # basic RFC connection with pyrfc - try: - conn = Connection(user=conn_username, passwd=conn_password, ashost=host, sysnr=sysnr, client=client) - except Exception as err: - result['error'] = str(err) - result['msg'] = 'Something went wrong connecting to the SAP system.' - module.fail_json(**result) - - # build parameter dict of dict - company_params = build_company_params(name, name_2, country, time_zone, city, post_code, street, street_no, e_mail) - - if state == "absent": - raw = call_rfc_method(conn, 'BAPI_COMPANY_DELETE', {'COMPANY': company_id}) - - if state == "present": - raw = call_rfc_method(conn, 'BAPI_COMPANY_CLONE', - {'METHOD': {'USMETHOD': 'COMPANY_CLONE'}, 'COMPANY': company_id, 'COMP_DATA': company_params}) - - analysed = return_analysis(raw) - - result['out'] = raw - - result['changed'] = analysed[0]['change'] - result['msg'] = analysed[2]['msg'] - - if analysed[1]['failed']: - module.fail_json(**result) - - module.exit_json(**result) - - -def main(): - run_module() - - -if __name__ == '__main__': - main() diff --git a/ansible_collections/community/sap/plugins/modules/sap_snote.py b/ansible_collections/community/sap/plugins/modules/sap_snote.py deleted file mode 100644 index 24f393927..000000000 --- a/ansible_collections/community/sap/plugins/modules/sap_snote.py +++ /dev/null @@ -1,258 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: (c) 2021, Rainer Leber <rainerleber@gmail.com> <rainer.leber@sva.de> -# 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: sap_snote - -short_description: This module will upload and (de)implements C(SNOTES) in a SAP S4HANA environment. - -version_added: "1.0.0" - -description: - - The C(sap_snote) module depends on C(pyrfc) Python library (version 2.4.0 and upwards). - Depending on distribution you are using, you may need to install additional packages to - have these available. - - This module will use the Function Group C(SCWB_API). - - The C(TMS) must be configured at first. - - Integrating SNOTES cannot be done via C(DDIC)- or C(SAP*)-User. -options: - state: - description: - - The decision what to do with the SNOTE. - - Could be C('present'), C('absent') - default: 'present' - choices: - - 'present' - - 'absent' - required: false - type: str - conn_username: - description: The required username for the SAP system. - required: true - type: str - conn_password: - description: The required password for the SAP system. - required: true - type: str - host: - description: The required host for the SAP system. Can be either an FQDN or IP Address. - required: true - type: str - sysnr: - description: - - The system number of the SAP system. - - You must quote the value to ensure retaining the leading zeros. - required: false - default: '01' - type: str - client: - description: - - The client number to connect to. - - You must quote the value to ensure retaining the leading zeros. - required: false - default: '000' - type: str - snote_path: - description: - - The path to the extracted SNOTE txt file. - - The File could be extracted from SAR package. - - If C(snote_path) is not provided, the C(snote) parameter must be defined. - - The SNOTE txt file must be at a place where the SAP System is authorized for. For example C(/usr/sap/trans/files). - required: false - type: str - snote: - description: - - With the C(snote) paramter only implementation and deimplementation will work. - - Upload SNOTES to the System is only available if C(snote_path) is provided. - required: false - type: str - -requirements: - - pyrfc >= 2.4.0 - -author: - - Rainer Leber (@rainerleber) -''' - -EXAMPLES = r''' -- name: test snote module - hosts: localhost - tasks: - - name: implement SNOTE - community.sap.sap_snote: - conn_username: 'DDIC' - conn_password: 'Passwd1234' - host: 192.168.1.100 - sysnr: '01' - client: '000' - state: present - snote_path: /usr/sap/trans/tmp/0002949148.txt - -- name: test snote module without path - hosts: localhost - tasks: - - name: deimplement SNOTE - community.sap.sap_snote: - conn_username: 'DDIC' - conn_password: 'Passwd1234' - host: 192.168.1.100 - sysnr: '01' - client: '000' - state: absent - snote: 0002949148 - -''' - -RETURN = r''' -msg: - description: A small execution description. - type: str - returned: always - sample: 'SNOTE 000298026 implemented.' -out: - description: A complete description of the SNOTE implementation. If this is available. - type: list - elements: dict - returned: always - sample: '{ - "RETURN": [{"ES_MSG": { "MSGNO": "000", "MSGTY": "", "MSGTXT": "", "MSGV1": "" }, - "ET_MSG": [], - "EV_RC": 0, - "ET_MISSING_NOTES": [], - "IT_FILENAME": [{"FILENAME": "/usr/sap/trans/tmp/0002980265.txt"}], - "IT_NOTES": [{"NUMM": "0002980265", "VERSNO": "0000"}] - }]}' -''' - -from ansible.module_utils.basic import AnsibleModule, missing_required_lib -from os import path as os_path -import traceback -try: - from pyrfc import Connection -except ImportError: - HAS_PYRFC_LIBRARY = False - ANOTHER_LIBRARY_IMPORT_ERROR = traceback.format_exc() -else: - HAS_PYRFC_LIBRARY = True - - -def call_rfc_method(connection, method_name, kwargs): - # PyRFC call function - return connection.call(method_name, **kwargs) - - -def check_implementation(conn, snote): - check_implemented = call_rfc_method(conn, 'SCWB_API_GET_NOTES_IMPLEMENTED', {}) - for snote_list in check_implemented['ET_NOTES_IMPL']: - if snote in snote_list['NUMM']: - return True - return False - - -def run_module(): - module = AnsibleModule( - argument_spec=dict( - state=dict(default='present', choices=['absent', 'present']), - conn_username=dict(type='str', required=True), - conn_password=dict(type='str', required=True, no_log=True), - host=dict(type='str', required=True), - sysnr=dict(type='str', default="01"), - client=dict(type='str', default="000"), - snote_path=dict(type='str', required=False), - snote=dict(type='str', required=False), - ), - required_one_of=[('snote_path', 'snote')], - supports_check_mode=False, - ) - result = dict(changed=False, msg='', out={}, error='') - raw = "" - post_check = False - - params = module.params - - state = params['state'] - conn_username = (params['conn_username']).upper() - conn_password = params['conn_password'] - host = params['host'] - sysnr = (params['sysnr']).zfill(2) - client = params['client'] - - path = params['snote_path'] - snote = params['snote'] - - if not HAS_PYRFC_LIBRARY: - module.fail_json( - msg=missing_required_lib('pyrfc'), - exception=ANOTHER_LIBRARY_IMPORT_ERROR) - - if conn_username == "DDIC" or conn_username == "SAP*": - result['msg'] = 'User C(DDIC) or C(SAP*) not allowed for this operation.' - module.fail_json(**result) - - # basic RFC connection with pyrfc - try: - conn = Connection(user=conn_username, passwd=conn_password, ashost=host, sysnr=sysnr, client=client) - except Exception as err: - result['error'] = str(err) - result['msg'] = 'Something went wrong connecting to the SAP system.' - module.fail_json(**result) - - # pre evaluation of parameters - if path is not None: - if path.endswith('.txt'): - # splits snote number from path and txt extension - snote = os_path.basename(os_path.normpath(path)).split('.')[0] - else: - result['msg'] = 'The path must include the extracted snote file and ends with txt.' - module.fail_json(**result) - - pre_check = check_implementation(conn, snote) - - if state == "absent" and pre_check: - raw = call_rfc_method(conn, 'SCWB_API_NOTES_DEIMPLEMENT', {'IT_NOTES': [snote]}) - - if state == "present" and not pre_check: - if path: - raw_upload = call_rfc_method(conn, 'SCWB_API_UPLOAD_NOTES', {'IT_FILENAME': [path], 'IT_NOTES': [snote]}) - if raw_upload['EV_RC'] != 0: - result['out'] = raw_upload - result['msg'] = raw_upload['ES_MSG']['MSGTXT'] - module.fail_json(**result) - - raw = call_rfc_method(conn, 'SCWB_API_NOTES_IMPLEMENT', {'IT_NOTES': [snote]}) - queued = call_rfc_method(conn, 'SCWB_API_CINST_QUEUE_GET', {}) - - if queued['ET_MANUAL_ACTIVITIES']: - raw = call_rfc_method(conn, 'SCWB_API_CONFIRM_MAN_ACTIVITY', {}) - - if raw: - if raw['EV_RC'] == 0: - post_check = check_implementation(conn, snote) - if post_check and state == "present": - result['changed'] = True - result['msg'] = 'SNOTE "{0}" implemented.'.format(snote) - if not post_check and state == "absent": - result['changed'] = True - result['msg'] = 'SNOTE "{0}" deimplemented.'.format(snote) - else: - result['msg'] = "Something went wrong." - module.fail_json(**result) - result['out'] = raw - else: - result['msg'] = "Nothing to do." - - module.exit_json(**result) - - -def main(): - run_module() - - -if __name__ == '__main__': - main() diff --git a/ansible_collections/community/sap/plugins/modules/sap_system_facts.py b/ansible_collections/community/sap/plugins/modules/sap_system_facts.py deleted file mode 100644 index b5f4eb9b6..000000000 --- a/ansible_collections/community/sap/plugins/modules/sap_system_facts.py +++ /dev/null @@ -1,206 +0,0 @@ -#!/usr/bin/python - -# Copyright: (c) 2022, Rainer Leber rainerleber@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: sap_system_facts - -short_description: Gathers SAP facts in a host - -version_added: "1.0.0" - -description: - - This facts module gathers SAP system facts about the running instance. - -author: - - Rainer Leber (@rainerleber) - -notes: - - Supports C(check_mode). -''' - -EXAMPLES = r''' -- name: Return SAP system ansible_facts - community.sap.sap_system_fact: -''' - -RETURN = r''' -# These are examples of possible return values, -# and in general should use other names for return values. -ansible_facts: - description: Facts to add to ansible_facts. - returned: always - type: list - elements: dict - contains: - sap: - description: Facts about the running SAP system. - type: list - elements: dict - returned: When SAP system fact is present - sample: [ - { - "InstanceType": "NW", - "NR": "00", - "SID": "ABC", - "TYPE": "ASCS" - }, - { - "InstanceType": "NW", - "NR": "01", - "SID": "ABC", - "TYPE": "PAS" - }, - { - "InstanceType": "HANA", - "NR": "02", - "SID": "HDB", - "TYPE": "HDB" - }, - { - "InstanceType": "NW", - "NR": "80", - "SID": "WEB", - "TYPE": "WebDisp" - } - ] -''' - -from ansible.module_utils.basic import AnsibleModule -import os -import re - - -def get_all_hana_sid(): - hana_sid = list() - if os.path.isdir("/hana/shared"): - # /hana/shared directory exists - for sid in os.listdir('/hana/shared'): - if os.path.isdir("/usr/sap/" + sid): - hana_sid = hana_sid + [sid] - if hana_sid: - return hana_sid - - -def get_all_nw_sid(): - nw_sid = list() - if os.path.isdir("/sapmnt"): - # /sapmnt directory exists - for sid in os.listdir('/sapmnt'): - if os.path.isdir("/usr/sap/" + sid): - nw_sid = nw_sid + [sid] - else: - # Check to see if /sapmnt/SID/sap_bobj exists - if os.path.isdir("/sapmnt/" + sid + "/sap_bobj"): - # is a bobj system - nw_sid = nw_sid + [sid] - if nw_sid: - return nw_sid - - -def get_hana_nr(sids, module): - hana_list = list() - for sid in sids: - for instance in os.listdir('/usr/sap/' + sid): - if 'HDB' in instance: - instance_nr = instance[-2:] - # check if instance number exists - command = [module.get_bin_path('/usr/sap/hostctrl/exe/sapcontrol', required=True)] - command.extend(['-nr', instance_nr, '-function', 'GetProcessList']) - check_instance = module.run_command(command, check_rc=False) - # sapcontrol returns c(0 - 5) exit codes only c(1) is unavailable - if check_instance[0] != 1: - hana_list.append({'NR': instance_nr, 'SID': sid, 'TYPE': 'HDB', 'InstanceType': 'HANA'}) - return hana_list - - -def get_nw_nr(sids, module): - nw_list = list() - type = "" - for sid in sids: - for instance in os.listdir('/usr/sap/' + sid): - instance_nr = instance[-2:] - command = [module.get_bin_path('/usr/sap/hostctrl/exe/sapcontrol', required=True)] - # check if returned instance_nr is a number because sapcontrol returns all if a random string is provided - if instance_nr.isdigit(): - command.extend(['-nr', instance_nr, '-function', 'GetInstanceProperties']) - check_instance = module.run_command(command, check_rc=False) - if check_instance[0] != 1: - for line in check_instance[1].splitlines(): - if re.search('INSTANCE_NAME', line): - # convert to list and extract last - type_raw = (line.strip('][').split(', '))[-1] - # split instance number - type = type_raw[:-2] - nw_list.append({'NR': instance_nr, 'SID': sid, 'TYPE': get_instance_type(type), 'InstanceType': 'NW'}) - return nw_list - - -def get_instance_type(raw_type): - if raw_type[0] == "D": - # It's a PAS - type = "PAS" - elif raw_type[0] == "A": - # It's an ASCS - type = "ASCS" - elif raw_type[0] == "W": - # It's a Webdisp - type = "WebDisp" - elif raw_type[0] == "J": - # It's a Java - type = "Java" - elif raw_type[0] == "S": - # It's an SCS - type = "SCS" - elif raw_type[0] == "E": - # It's an ERS - type = "ERS" - else: - # Unknown instance type - type = "XXX" - return type - - -def run_module(): - module_args = dict() - system_result = list() - - result = dict( - changed=False, - ansible_facts=dict(), - ) - - module = AnsibleModule( - argument_spec=module_args, - supports_check_mode=True, - ) - - hana_sid = get_all_hana_sid() - if hana_sid: - system_result = system_result + get_hana_nr(hana_sid, module) - - nw_sid = get_all_nw_sid() - if nw_sid: - system_result = system_result + get_nw_nr(nw_sid, module) - - if system_result: - result['ansible_facts'] = {'sap': system_result} - else: - result['ansible_facts'] - - if module.check_mode: - module.exit_json(**result) - - module.exit_json(**result) - - -def main(): - run_module() - - -if __name__ == '__main__': - main() diff --git a/ansible_collections/community/sap/plugins/modules/sap_task_list_execute.py b/ansible_collections/community/sap/plugins/modules/sap_task_list_execute.py deleted file mode 100644 index 0ae25903f..000000000 --- a/ansible_collections/community/sap/plugins/modules/sap_task_list_execute.py +++ /dev/null @@ -1,340 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: (c) 2021, Rainer Leber <rainerleber@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: sap_task_list_execute -short_description: Perform SAP Task list execution -version_added: "0.1.0" -description: - - The M(community.sap.sap_task_list_execute) module depends on C(pyrfc) Python library (version 2.4.0 and upwards). - Depending on distribution you are using, you may need to install additional packages to - have these available. - - Tasks in the task list which requires manual activities will be confirmed automatically. - - This module will use the RFC package C(STC_TM_API). - -requirements: - - pyrfc >= 2.4.0 - - xmltodict - -options: - conn_username: - description: The required username for the SAP system. - required: true - type: str - conn_password: - description: The required password for the SAP system. - required: true - type: str - host: - description: The required host for the SAP system. Can be either an FQDN or IP Address. - required: true - type: str - sysnr: - description: - - The system number of the SAP system. - - You must quote the value to ensure retaining the leading zeros. - default: '00' - type: str - client: - description: - - The client number to connect to. - - You must quote the value to ensure retaining the leading zeros. - default: '000' - type: str - task_to_execute: - description: The task list which will be executed. - required: true - type: str - task_parameters: - description: - - The tasks and the parameters for execution. - - If the task list does not need any parameters, this could be empty. - - If only specific tasks from the task list should be executed, - the tasks even when no parameter is needed must be provided - alongside with the module parameter I(task_skip=true). - type: list - elements: dict - suboptions: - TASKNAME: - description: The name of the task in the task list. - type: str - required: true - FIELDNAME: - description: The name of the field of the task. - type: str - VALUE: - description: The value which have to be set. - type: raw - task_settings: - description: - - Setting for the execution of the task list. This can be the following as in TCODE SE80 described. - Check Mode C(CHECKRUN), Background Processing Active C(BATCH) (this is the default value), - Asynchronous Execution C(ASYNC), Trace Mode C(TRACE), Server Name C(BATCH_TARGET). - default: ['BATCH'] - type: list - elements: str - task_skip: - description: - - If this parameter is C(true), not defined tasks in I(task_parameters) are skipped. - - This could be the case when only certain tasks should run from the task list. - default: false - type: bool - -notes: - - Does not support C(check_mode). Always returns that the state has changed. -author: - - Rainer Leber (@rainerleber) -''' - -EXAMPLES = r''' -# Pass in a message -- name: Test task execution - community.sap.sap_task_list_execute: - conn_username: DDIC - conn_password: Passwd1234 - host: 10.1.8.10 - sysnr: '01' - client: '000' - task_to_execute: SAP_BASIS_SSL_CHECK - task_settings: batch - -- name: Pass in input parameters - community.sap.sap_task_list_execute: - conn_username: DDIC - conn_password: Passwd1234 - host: 10.1.8.10 - sysnr: '00' - client: '000' - task_to_execute: SAP_BASIS_SSL_CHECK - task_parameters : - - { 'TASKNAME': 'CL_STCT_CHECK_SEC_CRYPTO', 'FIELDNAME': 'P_OPT2', 'VALUE': 'X' } - - TASKNAME: CL_STCT_CHECK_SEC_CRYPTO - FIELDNAME: P_OPT3 - VALUE: X - task_settings: batch - -# Exported environment variables -- name: Hint if module will fail with error message like ImportError libsapnwrfc.so... - community.sap.sap_task_list_execute: - conn_username: DDIC - conn_password: Passwd1234 - host: 10.1.8.10 - sysnr: '00' - client: '000' - task_to_execute: SAP_BASIS_SSL_CHECK - task_settings: batch - environment: - SAPNWRFC_HOME: /usr/local/sap/nwrfcsdk - LD_LIBRARY_PATH: /usr/local/sap/nwrfcsdk/lib -''' - -RETURN = r''' -msg: - description: A small execution description. - type: str - returned: always - sample: 'Successful' -out: - description: A complete description of the executed tasks. If this is available. - type: list - elements: dict - returned: on success - sample: [...,{ - "LOG": { - "STCTM_S_LOG": [ - { - "ACTIVITY": "U_CONFIG", - "ACTIVITY_DESCR": "Configuration changed", - "DETAILS": null, - "EXEC_ID": "20210728184903.815739", - "FIELD": null, - "ID": "STC_TASK", - "LOG_MSG_NO": "000000", - "LOG_NO": null, - "MESSAGE": "For radiobutton group ICM too many options are set; choose only one option", - "MESSAGE_V1": "ICM", - "MESSAGE_V2": null, - "MESSAGE_V3": null, - "MESSAGE_V4": null, - "NUMBER": "048", - "PARAMETER": null, - "PERIOD": "M", - "PERIOD_DESCR": "Maintenance", - "ROW": "0", - "SRC_LINE": "170", - "SRC_OBJECT": "CL_STCTM_REPORT_UI IF_STCTM_UI_TASK~SET_PARAMETERS", - "SYSTEM": null, - "TIMESTMP": "20210728184903", - "TSTPNM": "DDIC", - "TYPE": "E" - },... - ]}}] -''' - -from ansible.module_utils.basic import AnsibleModule, missing_required_lib -import traceback -try: - from pyrfc import Connection -except ImportError: - HAS_PYRFC_LIBRARY = False - PYRFC_LIBRARY_IMPORT_ERROR = traceback.format_exc() -else: - HAS_PYRFC_LIBRARY = True -try: - import xmltodict -except ImportError: - HAS_XMLTODICT_LIBRARY = False - XMLTODICT_LIBRARY_IMPORT_ERROR = traceback.format_exc() -else: - HAS_XMLTODICT_LIBRARY = True - - -def call_rfc_method(connection, method_name, kwargs): - # PyRFC call function - return connection.call(method_name, **kwargs) - - -def process_exec_settings(task_settings): - # processes task settings to objects - exec_settings = {} - for settings in task_settings: - temp_dict = {settings.upper(): 'X'} - for key, value in temp_dict.items(): - exec_settings[key] = value - return exec_settings - - -def xml_to_dict(xml_raw): - try: - xml_parsed = xmltodict.parse(xml_raw, dict_constructor=dict) - xml_dict = xml_parsed['asx:abap']['asx:values']['SESSION']['TASKLIST'] - except KeyError: - xml_dict = "No logs available." - return xml_dict - - -def run_module(): - - params_spec = dict( - TASKNAME=dict(type='str', required=True), - FIELDNAME=dict(type='str'), - VALUE=dict(type='raw'), - ) - - # define available arguments/parameters a user can pass to the module - module = AnsibleModule( - argument_spec=dict( - # values for connection - conn_username=dict(type='str', required=True), - conn_password=dict(type='str', required=True, no_log=True), - host=dict(type='str', required=True), - sysnr=dict(type='str', default="00"), - client=dict(type='str', default="000"), - # values for execution tasks - task_to_execute=dict(type='str', required=True), - task_parameters=dict(type='list', elements='dict', options=params_spec), - task_settings=dict(type='list', elements='str', default=['BATCH']), - task_skip=dict(type='bool', default=False), - ), - supports_check_mode=False, - ) - result = dict(changed=False, msg='', out={}) - - params = module.params - - username = params['conn_username'].upper() - password = params['conn_password'] - host = params['host'] - sysnr = params['sysnr'] - client = params['client'] - - task_parameters = params['task_parameters'] - task_to_execute = params['task_to_execute'] - task_settings = params['task_settings'] - task_skip = params['task_skip'] - - if not HAS_PYRFC_LIBRARY: - module.fail_json( - msg=missing_required_lib('pyrfc'), - exception=PYRFC_LIBRARY_IMPORT_ERROR) - - if not HAS_XMLTODICT_LIBRARY: - module.fail_json( - msg=missing_required_lib('xmltodict'), - exception=XMLTODICT_LIBRARY_IMPORT_ERROR) - - # basic RFC connection with pyrfc - try: - conn = Connection(user=username, passwd=password, ashost=host, sysnr=sysnr, client=client) - except Exception as err: - result['error'] = str(err) - result['msg'] = 'Something went wrong connecting to the SAP system.' - module.fail_json(**result) - - try: - raw_params = call_rfc_method(conn, 'STC_TM_SCENARIO_GET_PARAMETERS', - {'I_SCENARIO_ID': task_to_execute}) - except Exception as err: - result['error'] = str(err) - result['msg'] = 'The task list does not exist.' - module.fail_json(**result) - exec_settings = process_exec_settings(task_settings) - # initialize session task - session_init = call_rfc_method(conn, 'STC_TM_SESSION_BEGIN', - {'I_SCENARIO_ID': task_to_execute, - 'I_INIT_ONLY': 'X'}) - # Confirm Tasks which requires manual activities from Task List Run - for task in raw_params['ET_PARAMETER']: - call_rfc_method(conn, 'STC_TM_TASK_CONFIRM', - {'I_SESSION_ID': session_init['E_SESSION_ID'], - 'I_TASKNAME': task['TASKNAME']}) - if task_skip: - for task in raw_params['ET_PARAMETER']: - call_rfc_method(conn, 'STC_TM_TASK_SKIP', - {'I_SESSION_ID': session_init['E_SESSION_ID'], - 'I_TASKNAME': task['TASKNAME'], 'I_SKIP_DEP_TASKS': 'X'}) - # unskip defined tasks and set parameters - if task_parameters is not None: - for task in task_parameters: - call_rfc_method(conn, 'STC_TM_TASK_UNSKIP', - {'I_SESSION_ID': session_init['E_SESSION_ID'], - 'I_TASKNAME': task['TASKNAME'], 'I_UNSKIP_DEP_TASKS': 'X'}) - - call_rfc_method(conn, 'STC_TM_SESSION_SET_PARAMETERS', - {'I_SESSION_ID': session_init['E_SESSION_ID'], - 'IT_PARAMETER': task_parameters}) - # start the task - try: - session_start = call_rfc_method(conn, 'STC_TM_SESSION_RESUME', - {'I_SESSION_ID': session_init['E_SESSION_ID'], - 'IS_EXEC_SETTINGS': exec_settings}) - except Exception as err: - result['error'] = str(err) - result['msg'] = 'Something went wrong. See error.' - module.fail_json(**result) - # get task logs because the execution may successfully but the tasks shows errors or warnings - # returned value is ABAPXML https://help.sap.com/doc/abapdocu_755_index_htm/7.55/en-US/abenabap_xslt_asxml_general.htm - session_log = call_rfc_method(conn, 'STC_TM_SESSION_GET_LOG', - {'I_SESSION_ID': session_init['E_SESSION_ID']}) - - task_list = xml_to_dict(session_log['E_LOG']) - - result['changed'] = True - result['msg'] = session_start['E_STATUS_DESCR'] - result['out'] = task_list - - module.exit_json(**result) - - -def main(): - run_module() - - -if __name__ == '__main__': - main() diff --git a/ansible_collections/community/sap/plugins/modules/sap_user.py b/ansible_collections/community/sap/plugins/modules/sap_user.py deleted file mode 100644 index f83472657..000000000 --- a/ansible_collections/community/sap/plugins/modules/sap_user.py +++ /dev/null @@ -1,499 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: (c) 2021, Rainer Leber <rainerleber@gmail.com> <rainer.leber@sva.de> -# 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: sap_user -short_description: This module will manage a user entities in a SAP S4/HANA environment -version_added: "1.0.0" -description: - - The M(community.sap.sap_user) module depends on C(pyrfc) Python library (version 2.4.0 and upwards). - Depending on distribution you are using, you may need to install additional packages to - have these available. - - This module will use the following user BAPIs to manage user entities. - - C(BAPI_USER_GET_DETAIL) - - C(BAPI_USER_DELETE) - - C(BAPI_USER_CREATE1) - - C(BAPI_USER_CHANGE) - - C(BAPI_USER_ACTGROUPS_ASSIGN) - - C(BAPI_USER_PROFILES_ASSIGN) - - C(BAPI_USER_UNLOCK) - - C(BAPI_USER_LOCK) -options: - state: - description: - - The decision what to do with the user. - default: 'present' - choices: - - 'present' - - 'absent' - - 'lock' - - 'unlock' - required: false - type: str - force: - description: - - Must be C('True') if the password or type should be overwritten. - default: False - required: false - type: bool - conn_username: - description: The required username for the SAP system. - required: true - type: str - conn_password: - description: The required password for the SAP system. - required: true - type: str - host: - description: The required host for the SAP system. Can be either an FQDN or IP Address. - required: true - type: str - sysnr: - description: - - The system number of the SAP system. - - You must quote the value to ensure retaining the leading zeros. - default: '00' - type: str - client: - description: - - The client number to connect to. - - You must quote the value to ensure retaining the leading zeros. - default: '000' - type: str - username: - description: - - The username. - type: str - required: true - firstname: - description: - - The Firstname of the user in the SAP system. - type: str - required: false - lastname: - description: - - The lastname of the user in the SAP system. - type: str - required: false - email: - description: - - The email address of the user in the SAP system. - type: str - required: false - password: - description: - - The password for the user in the SAP system. - type: str - required: false - useralias: - description: - - The alias for the user in the SAP system. - type: str - required: false - user_type: - description: - - The type for the user in the SAP system. - - C('A') Dialog user, C('B') System User, C('C') Communication User, - C('S') Service User, C('L') Reference User. - - Must be in uppercase. - type: str - required: false - default: 'A' - choices: ['A', 'B', 'C', 'S', 'L'] - company: - description: - - The specific company the user belongs to. - - The company name must be available in the SAP system. - type: str - required: false - profiles: - description: - - Assign profiles to the user. - - Should be in uppercase, for example C('SAP_NEW') or C('SAP_ALL'). - type: list - elements: str - default: [''] - required: false - roles: - description: - - Assign roles to the user. - type: list - elements: str - default: [''] - required: false - -requirements: - - pyrfc >= 2.4.0 -author: - - Rainer Leber (@rainerleber) -notes: - - Does not support C(check_mode). -''' - -EXAMPLES = r''' -- name: Create SAP User - community.sap.sap_user: - conn_username: 'DDIC' - conn_password: 'Test123' - host: 192.168.1.150 - sysnr: '01' - client: '000' - state: present - username: ADMIN - firstname: first_admin - lastname: last_admin - email: admin@test.de - password: Test123456 - useralias: ADMIN - company: DEFAULT_COMPANY - roles: - - "SAP_ALL" - -- name: Force change SAP User - community.sap.sap_user: - conn_username: 'DDIC' - conn_password: 'Test123' - host: 192.168.1.150 - sysnr: '01' - client: '000' - state: present - force: true - username: ADMIN - firstname: first_admin - lastname: last_admin - email: admin@test.de - password: Test123456 - useralias: ADMIN - company: DEFAULT_COMPANY - roles: - - "SAP_ALL" - -- name: Delete SAP User - community.sap.sap_user: - conn_username: 'DDIC' - conn_password: 'Test123' - host: 192.168.1.150 - sysnr: '01' - client: '000' - state: absent - force: true - username: ADMIN - -- name: Unlock SAP User - community.sap.sap_user: - conn_username: 'DDIC' - conn_password: 'Test123' - host: 192.168.1.150 - sysnr: '01' - client: '000' - state: unlock - force: true - username: ADMIN -''' - -RETURN = r''' -msg: - description: A small execution description about the user action. - type: str - returned: always - sample: 'User ADMIN created' -out: - description: A detailed description about the user action. - type: list - elements: dict - returned: on success - sample: [...,{ - "RETURN": [ - { - "FIELD": "BNAME", - "ID": "01", - "LOG_MSG_NO": "000000", - "LOG_NO": "", - "MESSAGE": "User ADMIN created", - "MESSAGE_V1": "ADMIN", - "MESSAGE_V2": "", - "MESSAGE_V3": "", - "MESSAGE_V4": "", - "NUMBER": "102", - "PARAMETER": "", - "ROW": 0, - "SYSTEM": "", - "TYPE": "S" - } - ], - "SAPUSER_UUID_HIST": []}] -''' -from ansible.module_utils.basic import AnsibleModule, missing_required_lib -import traceback -import datetime -try: - from pyrfc import Connection -except ImportError: - HAS_PYRFC_LIBRARY = False - PYRFC_LIBRARY_IMPORT_ERROR = traceback.format_exc() -else: - HAS_PYRFC_LIBRARY = True - - -def add_to_dict(target_dict, target_key, value): - # Adds the given value to a dict as the key - # check if the given key is in the given dict yet - if target_key in target_dict: - return False - target_dict[target_key] = value - return True - - -def call_rfc_method(connection, method_name, kwargs): - # PyRFC call function - return connection.call(method_name, **kwargs) - - -def build_rfc_user_params(username, firstname, lastname, email, raw_password, - useralias, user_type, raw_company, user_change, force): - """Creates RFC parameters for Creating users""" - # define dicts in batch - params = dict() - address = dict() - password = dict() - alias = dict() - logondata = dict() - company = dict() - # for change parameters - addressx = dict() - passwordx = dict() - logondatax = dict() - companyx = dict() - # define username - add_to_dict(params, 'USERNAME', username) - # define Address - add_to_dict(address, 'FIRSTNAME', firstname) - add_to_dict(address, 'LASTNAME', lastname) - add_to_dict(address, 'E_MAIL', email) - # define Password - add_to_dict(password, 'BAPIPWD', raw_password) - # define Alias - add_to_dict(alias, 'USERALIAS', useralias) - # define LogonData - add_to_dict(logondata, 'GLTGV', datetime.date.today()) - add_to_dict(logondata, 'GLTGB', '20991231') - add_to_dict(logondata, 'USTYP', user_type) - # define company - add_to_dict(company, 'COMPANY', raw_company) - params['LOGONDATA'] = logondata - params['ADDRESS'] = address - params['COMPANY'] = company - params['ALIAS'] = alias - params['PASSWORD'] = password - # add change if user exists - if user_change and force: - add_to_dict(addressx, 'FIRSTNAME', 'X') - add_to_dict(addressx, 'LASTNAME', 'X') - add_to_dict(addressx, 'E_MAIL', 'X') - # define Password - add_to_dict(passwordx, 'BAPIPWD', 'X') - # define LogonData - add_to_dict(logondatax, 'USTYP', 'X') - # define company - add_to_dict(companyx, 'COMPANY', 'X') - params['LOGONDATAX'] = logondatax - params['ADDRESSX'] = addressx - params['COMPANYX'] = companyx - params['PASSWORDX'] = passwordx - return params - - -def user_role_assignment_build_rfc_params(roles, username): - rfc_table = [] - - for role_name in roles: - table_row = {'AGR_NAME': role_name} - - add_to_dict(table_row, 'FROM_DAT', datetime.date.today()) - add_to_dict(table_row, 'TO_DAT', '20991231') - - rfc_table.append(table_row) - - return { - 'USERNAME': username, - 'ACTIVITYGROUPS': rfc_table - } - - -def user_profile_assignment_build_rfc_params(profiles, username): - rfc_table = [] - - for profile_name in profiles: - table_row = {'BAPIPROF': profile_name} - rfc_table.append(table_row) - - return { - 'USERNAME': username, - 'PROFILES': rfc_table - } - - -def check_user(user_detail): - if len(user_detail['RETURN']) > 0: - for sub in user_detail['RETURN']: - if sub['NUMBER'] == '124': - return False - return True - - -def return_analysis(raw): - change = False - failed = False - for state in raw['RETURN']: - if state['TYPE'] == "E": - if state['NUMBER'] == '224' or state['NUMBER'] == '124': - change = False - else: - failed = True - if state['TYPE'] == "S": - if state['NUMBER'] != '029': - change = True - if state['TYPE'] == "W": - if state['NUMBER'] == '049' or state['NUMBER'] == '047': - change = True - if state['NUMBER'] == '255': - change = True - return [{"change": change}, {"failed": failed}] - - -def run_module(): - module = AnsibleModule( - argument_spec=dict( - # logical values - state=dict(default='present', choices=[ - 'absent', 'present', 'lock', 'unlock']), - force=dict(type='bool', default=False), - # values for connection - conn_username=dict(type='str', required=True), - conn_password=dict(type='str', required=True, no_log=True), - host=dict(type='str', required=True), - sysnr=dict(type='str', default="00"), - client=dict(type='str', default="000"), - # values for the new or existing user - username=dict(type='str', required=True), - firstname=dict(type='str', required=False), - lastname=dict(type='str', required=False), - email=dict(type='str', required=False), - password=dict(type='str', required=False, no_log=True), - useralias=dict(type='str', required=False), - user_type=dict(default="A", - choices=['A', 'B', 'C', 'S', 'L']), - company=dict(type='str', required=False), - # values for profile must a list - # Example ["SAP_NEW", "SAP_ALL"] - profiles=dict(type='list', elements='str', default=[""]), - # values for roles must a list - roles=dict(type='list', elements='str', default=[""]), - ), - supports_check_mode=False, - required_if=[('state', 'present', ['useralias', 'company'])] - ) - result = dict(changed=False, msg='', out='') - count = 0 - raw = "" - - params = module.params - - state = params['state'] - conn_username = (params['conn_username']).upper() - conn_password = params['conn_password'] - host = params['host'] - sysnr = params['sysnr'] - client = params['client'] - - username = (params['username']).upper() - firstname = params['firstname'] - lastname = params['lastname'] - email = params['email'] - password = params['password'] - force = params['force'] - if not params['useralias'] is None: - useralias = (params['useralias']).upper() - user_type = (params['user_type']).upper() - company = params['company'] - - profiles = params['profiles'] - roles = params['roles'] - - if not HAS_PYRFC_LIBRARY: - module.fail_json( - msg=missing_required_lib('pyrfc'), - exception=PYRFC_LIBRARY_IMPORT_ERROR) - - # basic RFC connection with pyrfc - try: - conn = Connection(user=conn_username, passwd=conn_password, ashost=host, sysnr=sysnr, client=client) - except Exception as err: - result['error'] = str(err) - result['msg'] = 'Something went wrong connecting to the SAP system.' - module.fail_json(**result) - - # user details - user_detail = call_rfc_method(conn, 'BAPI_USER_GET_DETAIL', {'USERNAME': username}) - user_exists = check_user(user_detail) - - if state == "absent": - if user_exists: - raw = call_rfc_method(conn, 'BAPI_USER_DELETE', {'USERNAME': username}) - - if state == "present": - user_params = build_rfc_user_params(username, firstname, lastname, email, password, useralias, user_type, company, user_exists, force) - if not user_exists: - raw = call_rfc_method(conn, 'BAPI_USER_CREATE1', user_params) - - if user_exists: - # check for address changes when user exists - user_no_changes = all((user_detail.get('ADDRESS')).get(k) == v for k, v in (user_params.get('ADDRESS')).items()) - if not user_no_changes or force: - raw = call_rfc_method(conn, 'BAPI_USER_CHANGE', user_params) - - call_rfc_method(conn, 'BAPI_USER_ACTGROUPS_ASSIGN', user_role_assignment_build_rfc_params(roles, username)) - - call_rfc_method(conn, 'BAPI_USER_PROFILES_ASSIGN', user_profile_assignment_build_rfc_params(profiles, username)) - - if state == "unlock": - if user_exists: - raw = call_rfc_method(conn, 'BAPI_USER_UNLOCK', {'USERNAME': username}) - - if state == "lock": - if user_exists: - raw = call_rfc_method(conn, 'BAPI_USER_LOCK', {'USERNAME': username}) - - # analyse return value - if raw != '': - analysed = return_analysis(raw) - - result['out'] = raw - - result['changed'] = analysed[0]['change'] - for msgs in raw['RETURN']: - if count > 0: - result['msg'] = result['msg'] + '\n' - result['msg'] = result['msg'] + msgs['MESSAGE'] - count = count + 1 - - if analysed[1]['failed']: - module.fail_json(**result) - else: - result['msg'] = "No changes where made." - - module.exit_json(**result) - - -def main(): - run_module() - - -if __name__ == '__main__': - main() diff --git a/ansible_collections/community/sap/plugins/modules/sapcar_extract.py b/ansible_collections/community/sap/plugins/modules/sapcar_extract.py deleted file mode 100644 index d586dd330..000000000 --- a/ansible_collections/community/sap/plugins/modules/sapcar_extract.py +++ /dev/null @@ -1,220 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: (c) 2021, Rainer Leber <rainerleber@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: sapcar_extract -short_description: Manages SAP SAPCAR archives -version_added: "0.1.0" -description: - - Provides support for unpacking C(sar)/C(car) files with the SAPCAR binary from SAP and pulling - information back into Ansible. -options: - path: - description: The path to the SAR/CAR file. - type: path - required: true - dest: - description: - - The destination where SAPCAR extracts the SAR file. Missing folders will be created. - If this parameter is not provided, it will unpack in the same folder as the SAR file. - type: path - binary_path: - description: - - The path to the SAPCAR binary, for example, C(/home/dummy/sapcar) or C(https://myserver/SAPCAR). - If this parameter is not provided, the module will look in C(PATH). - type: path - signature: - description: - - If C(true), the signature will be extracted. - default: false - type: bool - security_library: - description: - - The path to the security library, for example, C(/usr/sap/hostctrl/exe/libsapcrytp.so), for signature operations. - type: path - manifest: - description: - - The name of the manifest. - default: "SIGNATURE.SMF" - type: str - remove: - description: - - If C(true), the SAR/CAR file will be removed. B(This should be used with caution!) - default: false - type: bool -author: - - Rainer Leber (@RainerLeber) -notes: - - Always returns C(changed=true) in C(check_mode). -''' - -EXAMPLES = r""" -- name: Extract SAR file - community.sap.sapcar_extract: - path: "~/source/hana.sar" - -- name: Extract SAR file with destination - community.sap.sapcar_extract: - path: "~/source/hana.sar" - dest: "~/test/" - -- name: Extract SAR file with destination and download from webserver can be a fileshare as well - community.sap.sapcar_extract: - path: "~/source/hana.sar" - dest: "~/dest/" - binary_path: "https://myserver/SAPCAR" - -- name: Extract SAR file and delete SAR after extract - community.sap.sapcar_extract: - path: "~/source/hana.sar" - remove: true - -- name: Extract SAR file with manifest - community.sap.sapcar_extract: - path: "~/source/hana.sar" - signature: true - -- name: Extract SAR file with manifest and rename it - community.sap.sapcar_extract: - path: "~/source/hana.sar" - manifest: "MyNewSignature.SMF" - signature: true -""" - -import os -from tempfile import NamedTemporaryFile -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.urls import open_url -from ansible.module_utils.common.text.converters import to_native - - -def get_list_of_files(dir_name): - # create a list of file and directories - # names in the given directory - list_of_file = os.listdir(dir_name) - allFiles = list() - # Iterate over all the entries - for entry in list_of_file: - # Create full path - fullPath = os.path.join(dir_name, entry) - # If entry is a directory then get the list of files in this directory - if os.path.isdir(fullPath): - allFiles = allFiles + [fullPath] - allFiles = allFiles + get_list_of_files(fullPath) - else: - allFiles.append(fullPath) - return allFiles - - -def download_SAPCAR(binary_path, module): - bin_path = None - # download sapcar binary if url is provided otherwise path is returned - if binary_path is not None: - if binary_path.startswith('https://') or binary_path.startswith('http://'): - random_file = NamedTemporaryFile(delete=False) - with open_url(binary_path) as response: - with random_file as out_file: - data = response.read() - out_file.write(data) - os.chmod(out_file.name, 0o700) - bin_path = out_file.name - module.add_cleanup_file(bin_path) - else: - bin_path = binary_path - return bin_path - - -def check_if_present(command, path, dest, signature, manifest, module): - # manipulating output from SAR file for compare with already extracted files - iter_command = [command, '-tvf', path] - sar_out = module.run_command(iter_command)[1] - sar_raw = sar_out.split("\n")[1:] - if dest[-1] != "/": - dest = dest + "/" - sar_files = [dest + x.split(" ")[-1] for x in sar_raw if x] - # remove any SIGNATURE.SMF from list because it will not unpacked if signature is false - if not signature: - sar_files = [item for item in sar_files if not item.endswith('.SMF')] - # if signature is renamed manipulate files in list of sar file for compare. - if manifest != "SIGNATURE.SMF": - sar_files = [item for item in sar_files if not item.endswith('.SMF')] - sar_files = sar_files + [manifest] - # get extracted files if present - files_extracted = get_list_of_files(dest) - # compare extracted files with files in sar file - present = all(elem in files_extracted for elem in sar_files) - return present - - -def main(): - module = AnsibleModule( - argument_spec=dict( - path=dict(type='path', required=True), - dest=dict(type='path'), - binary_path=dict(type='path'), - signature=dict(type='bool', default=False), - security_library=dict(type='path'), - manifest=dict(type='str', default="SIGNATURE.SMF"), - remove=dict(type='bool', default=False), - ), - supports_check_mode=True, - ) - rc, out, err = [0, "", ""] - params = module.params - check_mode = module.check_mode - - path = params['path'] - dest = params['dest'] - signature = params['signature'] - security_library = params['security_library'] - manifest = params['manifest'] - remove = params['remove'] - - bin_path = download_SAPCAR(params['binary_path'], module) - - if dest is None: - dest_head_tail = os.path.split(path) - dest = dest_head_tail[0] + '/' - else: - if not os.path.exists(dest): - os.makedirs(dest, 0o755) - - if bin_path is not None: - command = [module.get_bin_path(bin_path, required=True)] - else: - try: - command = [module.get_bin_path('sapcar', required=True)] - except Exception as e: - module.fail_json(msg='Failed to find SAPCAR at the expected path or URL "{0}". Please check whether it is available: {1}' - .format(bin_path, to_native(e))) - - present = check_if_present(command[0], path, dest, signature, manifest, module) - - if not present: - command.extend(['-xvf', path, '-R', dest]) - if security_library: - command.extend(['-L', security_library]) - if signature: - command.extend(['-manifest', manifest]) - if not check_mode: - (rc, out, err) = module.run_command(command, check_rc=True) - changed = True - else: - changed = False - out = "already unpacked" - - if remove: - os.remove(path) - - module.exit_json(changed=changed, message=rc, stdout=out, - stderr=err, command=' '.join(command)) - - -if __name__ == '__main__': - main() diff --git a/ansible_collections/community/sap/plugins/modules/system/sap_snote.py b/ansible_collections/community/sap/plugins/modules/system/sap_snote.py deleted file mode 100644 index 24f393927..000000000 --- a/ansible_collections/community/sap/plugins/modules/system/sap_snote.py +++ /dev/null @@ -1,258 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: (c) 2021, Rainer Leber <rainerleber@gmail.com> <rainer.leber@sva.de> -# 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: sap_snote - -short_description: This module will upload and (de)implements C(SNOTES) in a SAP S4HANA environment. - -version_added: "1.0.0" - -description: - - The C(sap_snote) module depends on C(pyrfc) Python library (version 2.4.0 and upwards). - Depending on distribution you are using, you may need to install additional packages to - have these available. - - This module will use the Function Group C(SCWB_API). - - The C(TMS) must be configured at first. - - Integrating SNOTES cannot be done via C(DDIC)- or C(SAP*)-User. -options: - state: - description: - - The decision what to do with the SNOTE. - - Could be C('present'), C('absent') - default: 'present' - choices: - - 'present' - - 'absent' - required: false - type: str - conn_username: - description: The required username for the SAP system. - required: true - type: str - conn_password: - description: The required password for the SAP system. - required: true - type: str - host: - description: The required host for the SAP system. Can be either an FQDN or IP Address. - required: true - type: str - sysnr: - description: - - The system number of the SAP system. - - You must quote the value to ensure retaining the leading zeros. - required: false - default: '01' - type: str - client: - description: - - The client number to connect to. - - You must quote the value to ensure retaining the leading zeros. - required: false - default: '000' - type: str - snote_path: - description: - - The path to the extracted SNOTE txt file. - - The File could be extracted from SAR package. - - If C(snote_path) is not provided, the C(snote) parameter must be defined. - - The SNOTE txt file must be at a place where the SAP System is authorized for. For example C(/usr/sap/trans/files). - required: false - type: str - snote: - description: - - With the C(snote) paramter only implementation and deimplementation will work. - - Upload SNOTES to the System is only available if C(snote_path) is provided. - required: false - type: str - -requirements: - - pyrfc >= 2.4.0 - -author: - - Rainer Leber (@rainerleber) -''' - -EXAMPLES = r''' -- name: test snote module - hosts: localhost - tasks: - - name: implement SNOTE - community.sap.sap_snote: - conn_username: 'DDIC' - conn_password: 'Passwd1234' - host: 192.168.1.100 - sysnr: '01' - client: '000' - state: present - snote_path: /usr/sap/trans/tmp/0002949148.txt - -- name: test snote module without path - hosts: localhost - tasks: - - name: deimplement SNOTE - community.sap.sap_snote: - conn_username: 'DDIC' - conn_password: 'Passwd1234' - host: 192.168.1.100 - sysnr: '01' - client: '000' - state: absent - snote: 0002949148 - -''' - -RETURN = r''' -msg: - description: A small execution description. - type: str - returned: always - sample: 'SNOTE 000298026 implemented.' -out: - description: A complete description of the SNOTE implementation. If this is available. - type: list - elements: dict - returned: always - sample: '{ - "RETURN": [{"ES_MSG": { "MSGNO": "000", "MSGTY": "", "MSGTXT": "", "MSGV1": "" }, - "ET_MSG": [], - "EV_RC": 0, - "ET_MISSING_NOTES": [], - "IT_FILENAME": [{"FILENAME": "/usr/sap/trans/tmp/0002980265.txt"}], - "IT_NOTES": [{"NUMM": "0002980265", "VERSNO": "0000"}] - }]}' -''' - -from ansible.module_utils.basic import AnsibleModule, missing_required_lib -from os import path as os_path -import traceback -try: - from pyrfc import Connection -except ImportError: - HAS_PYRFC_LIBRARY = False - ANOTHER_LIBRARY_IMPORT_ERROR = traceback.format_exc() -else: - HAS_PYRFC_LIBRARY = True - - -def call_rfc_method(connection, method_name, kwargs): - # PyRFC call function - return connection.call(method_name, **kwargs) - - -def check_implementation(conn, snote): - check_implemented = call_rfc_method(conn, 'SCWB_API_GET_NOTES_IMPLEMENTED', {}) - for snote_list in check_implemented['ET_NOTES_IMPL']: - if snote in snote_list['NUMM']: - return True - return False - - -def run_module(): - module = AnsibleModule( - argument_spec=dict( - state=dict(default='present', choices=['absent', 'present']), - conn_username=dict(type='str', required=True), - conn_password=dict(type='str', required=True, no_log=True), - host=dict(type='str', required=True), - sysnr=dict(type='str', default="01"), - client=dict(type='str', default="000"), - snote_path=dict(type='str', required=False), - snote=dict(type='str', required=False), - ), - required_one_of=[('snote_path', 'snote')], - supports_check_mode=False, - ) - result = dict(changed=False, msg='', out={}, error='') - raw = "" - post_check = False - - params = module.params - - state = params['state'] - conn_username = (params['conn_username']).upper() - conn_password = params['conn_password'] - host = params['host'] - sysnr = (params['sysnr']).zfill(2) - client = params['client'] - - path = params['snote_path'] - snote = params['snote'] - - if not HAS_PYRFC_LIBRARY: - module.fail_json( - msg=missing_required_lib('pyrfc'), - exception=ANOTHER_LIBRARY_IMPORT_ERROR) - - if conn_username == "DDIC" or conn_username == "SAP*": - result['msg'] = 'User C(DDIC) or C(SAP*) not allowed for this operation.' - module.fail_json(**result) - - # basic RFC connection with pyrfc - try: - conn = Connection(user=conn_username, passwd=conn_password, ashost=host, sysnr=sysnr, client=client) - except Exception as err: - result['error'] = str(err) - result['msg'] = 'Something went wrong connecting to the SAP system.' - module.fail_json(**result) - - # pre evaluation of parameters - if path is not None: - if path.endswith('.txt'): - # splits snote number from path and txt extension - snote = os_path.basename(os_path.normpath(path)).split('.')[0] - else: - result['msg'] = 'The path must include the extracted snote file and ends with txt.' - module.fail_json(**result) - - pre_check = check_implementation(conn, snote) - - if state == "absent" and pre_check: - raw = call_rfc_method(conn, 'SCWB_API_NOTES_DEIMPLEMENT', {'IT_NOTES': [snote]}) - - if state == "present" and not pre_check: - if path: - raw_upload = call_rfc_method(conn, 'SCWB_API_UPLOAD_NOTES', {'IT_FILENAME': [path], 'IT_NOTES': [snote]}) - if raw_upload['EV_RC'] != 0: - result['out'] = raw_upload - result['msg'] = raw_upload['ES_MSG']['MSGTXT'] - module.fail_json(**result) - - raw = call_rfc_method(conn, 'SCWB_API_NOTES_IMPLEMENT', {'IT_NOTES': [snote]}) - queued = call_rfc_method(conn, 'SCWB_API_CINST_QUEUE_GET', {}) - - if queued['ET_MANUAL_ACTIVITIES']: - raw = call_rfc_method(conn, 'SCWB_API_CONFIRM_MAN_ACTIVITY', {}) - - if raw: - if raw['EV_RC'] == 0: - post_check = check_implementation(conn, snote) - if post_check and state == "present": - result['changed'] = True - result['msg'] = 'SNOTE "{0}" implemented.'.format(snote) - if not post_check and state == "absent": - result['changed'] = True - result['msg'] = 'SNOTE "{0}" deimplemented.'.format(snote) - else: - result['msg'] = "Something went wrong." - module.fail_json(**result) - result['out'] = raw - else: - result['msg'] = "Nothing to do." - - module.exit_json(**result) - - -def main(): - run_module() - - -if __name__ == '__main__': - main() diff --git a/ansible_collections/community/sap/plugins/modules/system/sap_system_facts.py b/ansible_collections/community/sap/plugins/modules/system/sap_system_facts.py deleted file mode 100644 index b5f4eb9b6..000000000 --- a/ansible_collections/community/sap/plugins/modules/system/sap_system_facts.py +++ /dev/null @@ -1,206 +0,0 @@ -#!/usr/bin/python - -# Copyright: (c) 2022, Rainer Leber rainerleber@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: sap_system_facts - -short_description: Gathers SAP facts in a host - -version_added: "1.0.0" - -description: - - This facts module gathers SAP system facts about the running instance. - -author: - - Rainer Leber (@rainerleber) - -notes: - - Supports C(check_mode). -''' - -EXAMPLES = r''' -- name: Return SAP system ansible_facts - community.sap.sap_system_fact: -''' - -RETURN = r''' -# These are examples of possible return values, -# and in general should use other names for return values. -ansible_facts: - description: Facts to add to ansible_facts. - returned: always - type: list - elements: dict - contains: - sap: - description: Facts about the running SAP system. - type: list - elements: dict - returned: When SAP system fact is present - sample: [ - { - "InstanceType": "NW", - "NR": "00", - "SID": "ABC", - "TYPE": "ASCS" - }, - { - "InstanceType": "NW", - "NR": "01", - "SID": "ABC", - "TYPE": "PAS" - }, - { - "InstanceType": "HANA", - "NR": "02", - "SID": "HDB", - "TYPE": "HDB" - }, - { - "InstanceType": "NW", - "NR": "80", - "SID": "WEB", - "TYPE": "WebDisp" - } - ] -''' - -from ansible.module_utils.basic import AnsibleModule -import os -import re - - -def get_all_hana_sid(): - hana_sid = list() - if os.path.isdir("/hana/shared"): - # /hana/shared directory exists - for sid in os.listdir('/hana/shared'): - if os.path.isdir("/usr/sap/" + sid): - hana_sid = hana_sid + [sid] - if hana_sid: - return hana_sid - - -def get_all_nw_sid(): - nw_sid = list() - if os.path.isdir("/sapmnt"): - # /sapmnt directory exists - for sid in os.listdir('/sapmnt'): - if os.path.isdir("/usr/sap/" + sid): - nw_sid = nw_sid + [sid] - else: - # Check to see if /sapmnt/SID/sap_bobj exists - if os.path.isdir("/sapmnt/" + sid + "/sap_bobj"): - # is a bobj system - nw_sid = nw_sid + [sid] - if nw_sid: - return nw_sid - - -def get_hana_nr(sids, module): - hana_list = list() - for sid in sids: - for instance in os.listdir('/usr/sap/' + sid): - if 'HDB' in instance: - instance_nr = instance[-2:] - # check if instance number exists - command = [module.get_bin_path('/usr/sap/hostctrl/exe/sapcontrol', required=True)] - command.extend(['-nr', instance_nr, '-function', 'GetProcessList']) - check_instance = module.run_command(command, check_rc=False) - # sapcontrol returns c(0 - 5) exit codes only c(1) is unavailable - if check_instance[0] != 1: - hana_list.append({'NR': instance_nr, 'SID': sid, 'TYPE': 'HDB', 'InstanceType': 'HANA'}) - return hana_list - - -def get_nw_nr(sids, module): - nw_list = list() - type = "" - for sid in sids: - for instance in os.listdir('/usr/sap/' + sid): - instance_nr = instance[-2:] - command = [module.get_bin_path('/usr/sap/hostctrl/exe/sapcontrol', required=True)] - # check if returned instance_nr is a number because sapcontrol returns all if a random string is provided - if instance_nr.isdigit(): - command.extend(['-nr', instance_nr, '-function', 'GetInstanceProperties']) - check_instance = module.run_command(command, check_rc=False) - if check_instance[0] != 1: - for line in check_instance[1].splitlines(): - if re.search('INSTANCE_NAME', line): - # convert to list and extract last - type_raw = (line.strip('][').split(', '))[-1] - # split instance number - type = type_raw[:-2] - nw_list.append({'NR': instance_nr, 'SID': sid, 'TYPE': get_instance_type(type), 'InstanceType': 'NW'}) - return nw_list - - -def get_instance_type(raw_type): - if raw_type[0] == "D": - # It's a PAS - type = "PAS" - elif raw_type[0] == "A": - # It's an ASCS - type = "ASCS" - elif raw_type[0] == "W": - # It's a Webdisp - type = "WebDisp" - elif raw_type[0] == "J": - # It's a Java - type = "Java" - elif raw_type[0] == "S": - # It's an SCS - type = "SCS" - elif raw_type[0] == "E": - # It's an ERS - type = "ERS" - else: - # Unknown instance type - type = "XXX" - return type - - -def run_module(): - module_args = dict() - system_result = list() - - result = dict( - changed=False, - ansible_facts=dict(), - ) - - module = AnsibleModule( - argument_spec=module_args, - supports_check_mode=True, - ) - - hana_sid = get_all_hana_sid() - if hana_sid: - system_result = system_result + get_hana_nr(hana_sid, module) - - nw_sid = get_all_nw_sid() - if nw_sid: - system_result = system_result + get_nw_nr(nw_sid, module) - - if system_result: - result['ansible_facts'] = {'sap': system_result} - else: - result['ansible_facts'] - - if module.check_mode: - module.exit_json(**result) - - module.exit_json(**result) - - -def main(): - run_module() - - -if __name__ == '__main__': - main() diff --git a/ansible_collections/community/sap/plugins/modules/system/sap_task_list_execute.py b/ansible_collections/community/sap/plugins/modules/system/sap_task_list_execute.py deleted file mode 100644 index 0ae25903f..000000000 --- a/ansible_collections/community/sap/plugins/modules/system/sap_task_list_execute.py +++ /dev/null @@ -1,340 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: (c) 2021, Rainer Leber <rainerleber@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: sap_task_list_execute -short_description: Perform SAP Task list execution -version_added: "0.1.0" -description: - - The M(community.sap.sap_task_list_execute) module depends on C(pyrfc) Python library (version 2.4.0 and upwards). - Depending on distribution you are using, you may need to install additional packages to - have these available. - - Tasks in the task list which requires manual activities will be confirmed automatically. - - This module will use the RFC package C(STC_TM_API). - -requirements: - - pyrfc >= 2.4.0 - - xmltodict - -options: - conn_username: - description: The required username for the SAP system. - required: true - type: str - conn_password: - description: The required password for the SAP system. - required: true - type: str - host: - description: The required host for the SAP system. Can be either an FQDN or IP Address. - required: true - type: str - sysnr: - description: - - The system number of the SAP system. - - You must quote the value to ensure retaining the leading zeros. - default: '00' - type: str - client: - description: - - The client number to connect to. - - You must quote the value to ensure retaining the leading zeros. - default: '000' - type: str - task_to_execute: - description: The task list which will be executed. - required: true - type: str - task_parameters: - description: - - The tasks and the parameters for execution. - - If the task list does not need any parameters, this could be empty. - - If only specific tasks from the task list should be executed, - the tasks even when no parameter is needed must be provided - alongside with the module parameter I(task_skip=true). - type: list - elements: dict - suboptions: - TASKNAME: - description: The name of the task in the task list. - type: str - required: true - FIELDNAME: - description: The name of the field of the task. - type: str - VALUE: - description: The value which have to be set. - type: raw - task_settings: - description: - - Setting for the execution of the task list. This can be the following as in TCODE SE80 described. - Check Mode C(CHECKRUN), Background Processing Active C(BATCH) (this is the default value), - Asynchronous Execution C(ASYNC), Trace Mode C(TRACE), Server Name C(BATCH_TARGET). - default: ['BATCH'] - type: list - elements: str - task_skip: - description: - - If this parameter is C(true), not defined tasks in I(task_parameters) are skipped. - - This could be the case when only certain tasks should run from the task list. - default: false - type: bool - -notes: - - Does not support C(check_mode). Always returns that the state has changed. -author: - - Rainer Leber (@rainerleber) -''' - -EXAMPLES = r''' -# Pass in a message -- name: Test task execution - community.sap.sap_task_list_execute: - conn_username: DDIC - conn_password: Passwd1234 - host: 10.1.8.10 - sysnr: '01' - client: '000' - task_to_execute: SAP_BASIS_SSL_CHECK - task_settings: batch - -- name: Pass in input parameters - community.sap.sap_task_list_execute: - conn_username: DDIC - conn_password: Passwd1234 - host: 10.1.8.10 - sysnr: '00' - client: '000' - task_to_execute: SAP_BASIS_SSL_CHECK - task_parameters : - - { 'TASKNAME': 'CL_STCT_CHECK_SEC_CRYPTO', 'FIELDNAME': 'P_OPT2', 'VALUE': 'X' } - - TASKNAME: CL_STCT_CHECK_SEC_CRYPTO - FIELDNAME: P_OPT3 - VALUE: X - task_settings: batch - -# Exported environment variables -- name: Hint if module will fail with error message like ImportError libsapnwrfc.so... - community.sap.sap_task_list_execute: - conn_username: DDIC - conn_password: Passwd1234 - host: 10.1.8.10 - sysnr: '00' - client: '000' - task_to_execute: SAP_BASIS_SSL_CHECK - task_settings: batch - environment: - SAPNWRFC_HOME: /usr/local/sap/nwrfcsdk - LD_LIBRARY_PATH: /usr/local/sap/nwrfcsdk/lib -''' - -RETURN = r''' -msg: - description: A small execution description. - type: str - returned: always - sample: 'Successful' -out: - description: A complete description of the executed tasks. If this is available. - type: list - elements: dict - returned: on success - sample: [...,{ - "LOG": { - "STCTM_S_LOG": [ - { - "ACTIVITY": "U_CONFIG", - "ACTIVITY_DESCR": "Configuration changed", - "DETAILS": null, - "EXEC_ID": "20210728184903.815739", - "FIELD": null, - "ID": "STC_TASK", - "LOG_MSG_NO": "000000", - "LOG_NO": null, - "MESSAGE": "For radiobutton group ICM too many options are set; choose only one option", - "MESSAGE_V1": "ICM", - "MESSAGE_V2": null, - "MESSAGE_V3": null, - "MESSAGE_V4": null, - "NUMBER": "048", - "PARAMETER": null, - "PERIOD": "M", - "PERIOD_DESCR": "Maintenance", - "ROW": "0", - "SRC_LINE": "170", - "SRC_OBJECT": "CL_STCTM_REPORT_UI IF_STCTM_UI_TASK~SET_PARAMETERS", - "SYSTEM": null, - "TIMESTMP": "20210728184903", - "TSTPNM": "DDIC", - "TYPE": "E" - },... - ]}}] -''' - -from ansible.module_utils.basic import AnsibleModule, missing_required_lib -import traceback -try: - from pyrfc import Connection -except ImportError: - HAS_PYRFC_LIBRARY = False - PYRFC_LIBRARY_IMPORT_ERROR = traceback.format_exc() -else: - HAS_PYRFC_LIBRARY = True -try: - import xmltodict -except ImportError: - HAS_XMLTODICT_LIBRARY = False - XMLTODICT_LIBRARY_IMPORT_ERROR = traceback.format_exc() -else: - HAS_XMLTODICT_LIBRARY = True - - -def call_rfc_method(connection, method_name, kwargs): - # PyRFC call function - return connection.call(method_name, **kwargs) - - -def process_exec_settings(task_settings): - # processes task settings to objects - exec_settings = {} - for settings in task_settings: - temp_dict = {settings.upper(): 'X'} - for key, value in temp_dict.items(): - exec_settings[key] = value - return exec_settings - - -def xml_to_dict(xml_raw): - try: - xml_parsed = xmltodict.parse(xml_raw, dict_constructor=dict) - xml_dict = xml_parsed['asx:abap']['asx:values']['SESSION']['TASKLIST'] - except KeyError: - xml_dict = "No logs available." - return xml_dict - - -def run_module(): - - params_spec = dict( - TASKNAME=dict(type='str', required=True), - FIELDNAME=dict(type='str'), - VALUE=dict(type='raw'), - ) - - # define available arguments/parameters a user can pass to the module - module = AnsibleModule( - argument_spec=dict( - # values for connection - conn_username=dict(type='str', required=True), - conn_password=dict(type='str', required=True, no_log=True), - host=dict(type='str', required=True), - sysnr=dict(type='str', default="00"), - client=dict(type='str', default="000"), - # values for execution tasks - task_to_execute=dict(type='str', required=True), - task_parameters=dict(type='list', elements='dict', options=params_spec), - task_settings=dict(type='list', elements='str', default=['BATCH']), - task_skip=dict(type='bool', default=False), - ), - supports_check_mode=False, - ) - result = dict(changed=False, msg='', out={}) - - params = module.params - - username = params['conn_username'].upper() - password = params['conn_password'] - host = params['host'] - sysnr = params['sysnr'] - client = params['client'] - - task_parameters = params['task_parameters'] - task_to_execute = params['task_to_execute'] - task_settings = params['task_settings'] - task_skip = params['task_skip'] - - if not HAS_PYRFC_LIBRARY: - module.fail_json( - msg=missing_required_lib('pyrfc'), - exception=PYRFC_LIBRARY_IMPORT_ERROR) - - if not HAS_XMLTODICT_LIBRARY: - module.fail_json( - msg=missing_required_lib('xmltodict'), - exception=XMLTODICT_LIBRARY_IMPORT_ERROR) - - # basic RFC connection with pyrfc - try: - conn = Connection(user=username, passwd=password, ashost=host, sysnr=sysnr, client=client) - except Exception as err: - result['error'] = str(err) - result['msg'] = 'Something went wrong connecting to the SAP system.' - module.fail_json(**result) - - try: - raw_params = call_rfc_method(conn, 'STC_TM_SCENARIO_GET_PARAMETERS', - {'I_SCENARIO_ID': task_to_execute}) - except Exception as err: - result['error'] = str(err) - result['msg'] = 'The task list does not exist.' - module.fail_json(**result) - exec_settings = process_exec_settings(task_settings) - # initialize session task - session_init = call_rfc_method(conn, 'STC_TM_SESSION_BEGIN', - {'I_SCENARIO_ID': task_to_execute, - 'I_INIT_ONLY': 'X'}) - # Confirm Tasks which requires manual activities from Task List Run - for task in raw_params['ET_PARAMETER']: - call_rfc_method(conn, 'STC_TM_TASK_CONFIRM', - {'I_SESSION_ID': session_init['E_SESSION_ID'], - 'I_TASKNAME': task['TASKNAME']}) - if task_skip: - for task in raw_params['ET_PARAMETER']: - call_rfc_method(conn, 'STC_TM_TASK_SKIP', - {'I_SESSION_ID': session_init['E_SESSION_ID'], - 'I_TASKNAME': task['TASKNAME'], 'I_SKIP_DEP_TASKS': 'X'}) - # unskip defined tasks and set parameters - if task_parameters is not None: - for task in task_parameters: - call_rfc_method(conn, 'STC_TM_TASK_UNSKIP', - {'I_SESSION_ID': session_init['E_SESSION_ID'], - 'I_TASKNAME': task['TASKNAME'], 'I_UNSKIP_DEP_TASKS': 'X'}) - - call_rfc_method(conn, 'STC_TM_SESSION_SET_PARAMETERS', - {'I_SESSION_ID': session_init['E_SESSION_ID'], - 'IT_PARAMETER': task_parameters}) - # start the task - try: - session_start = call_rfc_method(conn, 'STC_TM_SESSION_RESUME', - {'I_SESSION_ID': session_init['E_SESSION_ID'], - 'IS_EXEC_SETTINGS': exec_settings}) - except Exception as err: - result['error'] = str(err) - result['msg'] = 'Something went wrong. See error.' - module.fail_json(**result) - # get task logs because the execution may successfully but the tasks shows errors or warnings - # returned value is ABAPXML https://help.sap.com/doc/abapdocu_755_index_htm/7.55/en-US/abenabap_xslt_asxml_general.htm - session_log = call_rfc_method(conn, 'STC_TM_SESSION_GET_LOG', - {'I_SESSION_ID': session_init['E_SESSION_ID']}) - - task_list = xml_to_dict(session_log['E_LOG']) - - result['changed'] = True - result['msg'] = session_start['E_STATUS_DESCR'] - result['out'] = task_list - - module.exit_json(**result) - - -def main(): - run_module() - - -if __name__ == '__main__': - main() |